{"id":278,"date":"2008-12-08T13:15:37","date_gmt":"2008-12-08T00:15:37","guid":{"rendered":"http:\/\/wp.davidbrebner.com\/?p=278"},"modified":"2013-04-28T20:53:33","modified_gmt":"2013-04-28T08:53:33","slug":"3d-bugs-in-vb","status":"publish","type":"post","link":"https:\/\/www.davidbrebner.com\/?p=278","title":{"rendered":"3D Bugs in VB"},"content":{"rendered":"<p>Back to the future for a tutorial from 2002 using VB6 and DirectX 8.0!!!<\/p>\n<p>\n\t<a href=\"images\/tutorials\/ver9_final.zip\">Download final sample code 559k<\/a><\/p>\n<p><h3>The absolutely enormous bug tutorial<\/h3>\n<p>\t\t\t\tWell, here we go.&nbsp; It\u2019s time for another huge tutorial.&nbsp; This<br \/>\n\t\t\t\tone covers DX8 cameras, lights, meshes, animated meshes, vector<br \/>\n\t\t\t\tand matrix arithmetic, a verlet physics engine, dds textures and<br \/>\n\t\t\t\talpha blending\u2026.. gasp<\/p>\n<p>\t\t\t\t<b>Inspiration for bugs<\/b><\/p>\n<p>\t\t\t\tMy inspiration for this tutorial was to build a physics engine<br \/>\n\t\t\t\tafter reading a gamasutra article by Thomas Jakobsen of IO<br \/>\n\t\t\t\tInteractive.&nbsp; The first actual work was to design a model for my<br \/>\n\t\t\t\tphysics entities.&nbsp; I was aiming for some kind of insect.<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" height=\"350\" src=\"images\/bugs\/image001.jpg\" width=\"468\" border=\"0\" p <><br \/>\n\t\t\t\t<br \/>\n&nbsp;<\/p>\n<p>\n\t\t\t\t<img decoding=\"async\" height=\"342\" src=\"images\/bugs\/image002.jpg\" width=\"456\" border=\"0\" p <><br \/>\n\t\t\t\t<br \/>\n\t\t\t\tIn the end the wasp character looked a bit complex, so I ended<br \/>\n\t\t\t\tup going for the beetle.&nbsp; The model was constructed using IK<br \/>\n\t\t\t\tchains to hold the various meshes together.&nbsp; I then key framed<br \/>\n\t\t\t\tan animation of the legs moving (in my interpretation of a bugs<br \/>\n\t\t\t\twalk).<\/p>\n<p>&nbsp;<\/p>\n<p>\n\t\t\t\t<img decoding=\"async\" height=\"281\" src=\"images\/bugs\/image003.gif\" width=\"420\" border=\"0\"><\/p>\n<p>\n\t\t\t\tThen I made textures from a photograph of some insects.<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" height=\"149\" src=\"images\/bugs\/image004.jpg\" width=\"372\" border=\"0\"><\/p>\n<p>\n\t\t\t\tThese textures where then applied to the appropriate meshes.&nbsp; I<br \/>\n\t\t\t\tended up simply going for a diffuse dark grey for the legs<br \/>\n\t\t\t\trather than try and map any textures.<\/p>\n<p>\t\t\t\tOnce that was done I used the DX SDK to convert my mesh file<br \/>\n\t\t\t\tinto a .X file.<\/p>\n<p><h3>Getting started<\/h3>\n<p>\t\t\t\tThe good news is that Microsoft have already done a lot of hard<br \/>\n\t\t\t\twork for you creating a pretty good framework of modules and<br \/>\n\t\t\t\tclasses along with the D3DX library.&nbsp; Overall I found it made<br \/>\n\t\t\t\tthe experience of creating a 3D app pretty painless.&nbsp; Some<br \/>\n\t\t\t\texplorations of matrix math later on hurt a lot more however : )<\/p>\n<p>\t\t\t\tThe first step was to be able to initialise the DX8 engine and<br \/>\n\t\t\t\tdraw me some lines.&nbsp; The idea is that this will provide the<br \/>\n\t\t\t\t\u2018wireframe\u2019 view of all my bouncing boxes once I create the<br \/>\n\t\t\t\tphysics engine.<\/p>\n<p>\t\t\t\tFirst I included the files provided by MS.&nbsp; D3danimaition.cls,<br \/>\n\t\t\t\td3dframe.cls, d3dinit.bas, d3dmesh.cls, d3dpick.cls,<br \/>\n\t\t\t\td3dshader.bas, d3dutil.bas<\/p>\n<p>\t\t\t\tThen I made a form, pasted on a picture control, and added some<br \/>\n\t\t\t\tdeclarations. <font face=\"Courier New\" size=\"2\"><\/p>\n<pre>Private Type CUSTOMVERTEX\r\n    v As D3DVECTOR\r\n    color As Long\r\n    tu As Single\r\n    tv As Single\r\nEnd Type\r\nConst D3DFVF_COLORVERTEX = (D3DFVF_XYZ Or D3DFVF_DIFFUSE Or D3DFVF_TEX1)\r\n\r\nDim m_ParticleTexture As Direct3DTexture8\r\nDim m_VertB As Direct3DVertexBuffer8\r\n\r\nDim m_Verts() As CUSTOMVERTEX\r\n<\/pre>\n<p>\t\t\t\t<\/font>This gives us a texture for the vertexes of our objects<br \/>\n\t\t\t\t(a Particle texture), a vertex buffer, and a array of vertexes<br \/>\n\t\t\t\tto fill with data.<\/p>\n<p>\t\t\t\tFrom here added a routine to initialise the 3d stuff.&nbsp; Luckily<br \/>\n\t\t\t\tMS already provide a bunch of stuff in the d3dinit.bas routines,<br \/>\n\t\t\t\tso it ends up fairly simple.. <font face=\"Courier New\" size=\"2\"><\/p>\n<pre>Private Sub initialiseD3D()\r\n    \r\n    'setup D3d\r\n    m_binit = D3DUtil_Init(Picture1.hwnd, True, 0, 0, D3DDEVTYPE_HAL, Me)\r\n    \r\n    'Set up some lights and camera\r\n    g_lWindowWidth = Picture1.ScaleWidth\r\n    g_lWindowHeight = Picture1.ScaleHeight\r\n    D3DUtil_SetupDefaultScene\r\n       \r\n    'position the camera\r\n    D3DUtil_SetupCamera vec3(0, 60, -300), vec3(0, 60, -200), vec3(0, 1, 0)\r\n\r\n    Dim v As CUSTOMVERTEX\r\n\r\n    Set m_ParticleTexture = D3DUtil_CreateTexture(g_dev, App.path &amp; &quot;\\Particle.bmp&quot;, D3DFMT_UNKNOWN)\r\n    \r\n    Set m_VertB = Nothing\r\n    Set m_VertB = g_dev.CreateVertexBuffer(4 * m_MaxParticles * Len(v), 0, D3DFVF_COLORVERTEX, D3DPOOL_MANAGED)\r\n    \r\nEnd Sub\r\n<\/pre>\n<p>\t\t\t\t<\/font>I called this routine from the Form_Load subroutine.<\/p>\n<p>\t\t\t\tI also added a command button to the page so I could have a way<br \/>\n\t\t\t\tto get it all started.&nbsp; This is the basic DX8 render loop below.<br \/>\n\t\t\t\t<font face=\"Courier New\" size=\"2\"><\/p>\n<pre>Private Sub Command1_Click()\r\n        Do\r\n        \r\n            \r\n            'Start the Scene\r\n            g_dev.BeginScene\r\n            \r\n            'clear the buffer\r\n            D3DUtil_ClearAll QBColor(8)\r\n            \r\n\t'DO THE DRAWING HERE\u2026.\r\n\r\n            'End the scene\r\n            g_dev.EndScene\r\n            \r\n            'update the screen...\r\n            D3DUtil_PresentAll g_focushwnd\r\n                        \r\n            DoEvents\r\n        Loop Until m_run = False\r\nEnd Sub<\/pre>\n<p>\t\t\t\t<\/font>Still nothing much to see though\u2026 Against my very visual<br \/>\n\t\t\t\tdevelopment style, the next stop is a physics simulation which<br \/>\n\t\t\t\twill be temporarily invisible!<\/p>\n<p><h3>Bouncing Verlet boxes<\/h3>\n<p>\t\t\t\tThere is heaps of \u2018interesting\u2019 literature I reviewed before<br \/>\n\t\t\t\tdeciding where to go with this simulation.&nbsp; Some of the<br \/>\n\t\t\t\texcellent work by Chris Heckler and Jeff Lander was very useful<br \/>\n\t\t\t\tas were some more theoretical papers by Baraff, Mirtich, and<br \/>\n\t\t\t\tWitkin.<\/p>\n<p>\t\t\t\tMy original intention was to perform correct collision detection<br \/>\n\t\t\t\tand restoration, but I ran out of time in my busy schedule, so<br \/>\n\t\t\t\tmaybe later perhaps : )<\/p>\n<p>\t\t\t\tSo why did I choose Verlet instead of a more traditional ODE<br \/>\n\t\t\t\tsolver?&nbsp; Well I chose it because of its simplicity and<br \/>\n\t\t\t\tstability.&nbsp; Using the ODE techniques you have to use integration<br \/>\n\t\t\t\tapproximations to work out what the new position of objects will<br \/>\n\t\t\t\tbe after a given timestep.&nbsp; In comparison Verlet implies a known<br \/>\n\t\t\t\tposition before and after the timestep, and it is the velocity<br \/>\n\t\t\t\tthat is an approximation.<\/p>\n<p>\t\t\t\tTo model real 3D objects using verlet, they are built out of<br \/>\n\t\t\t\tparticles with constraints.&nbsp; The constraints I have used are<br \/>\n\t\t\t\tsimply sticks of a given length between the particles.&nbsp; By<br \/>\n\t\t\t\tarranging them carefully you end up with boxes, pyramids, even<br \/>\n\t\t\t\tstick figures.<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" height=\"214\" src=\"images\/bugs\/image006.gif\" width=\"236\" border=\"0\"><\/p>\n<p>\n\t\t\t\tThis is the infamous box I am planning on making (could even be<br \/>\n\t\t\t\tconsidered a crate).&nbsp; The 8 particles make up its corners, and<br \/>\n\t\t\t\t12 sticks make up its sides.&nbsp; However it don\u2019t hold up that well<br \/>\n\t\t\t\twith only these 12 sticks, so we need to add cross bracing\u2026 more<br \/>\n\t\t\t\tlike this.<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" height=\"214\" src=\"images\/bugs\/image007.gif\" width=\"236\" border=\"0\"><\/p>\n<p>\n\t\t\t\tRight time to see how all this hangs together (literally).&nbsp;<br \/>\n\t\t\t\tRather than avoid the issue here is the code for the Verlet<br \/>\n\t\t\t\tintegration engine; <font face=\"Courier New\" size=\"2\"><\/p>\n<pre>'**************************************************\r\n' RIGID BODY PHYSICS SIMULATION\r\n'**************************************************\r\n' David Brebner, Unlimited Realities (2001)\r\n'**************************************************\r\n' Modeled using particles with join\r\n' Thanks to Jakobsen, Baraff, Mirtich, Witkin, Verlet\r\n'\r\n' note : verlet fixed time integration is used in\r\n'        this simulation for stablility\r\n'**************************************************\r\n\r\nPublic num_particles As Integer\r\n\r\nPublic num_join As Integer\r\nPublic join_p1(1000) As Long\r\nPublic join_p2(1000) As Long\r\nPublic join_rl(1000) As Long\r\n\r\nPublic m_curp(1000) As D3DVECTOR\r\n'position right now\r\n\r\nPublic m_oldp(1000) As D3DVECTOR\r\n'the old position\r\n\r\nPublic m_forc(1000) As D3DVECTOR\r\n'Force accumulation\r\n\r\nPublic m_grav As D3DVECTOR\r\n'Gravity\r\n\r\nPublic m_timeStep As Double\r\n'the time between integrations\r\n\r\nPublic Function TimeStep()\r\n    'this executed the requirements of the physics\r\n    'simulation for the current timestep\r\n\r\n    AccumulateForces\r\n\r\n    Verlet\r\n\r\n    SatisfyConstraints\r\n\r\nEnd Function\r\n\r\nPrivate Function Verlet()\r\n    Dim i As Integer\r\n    Dim tmp As D3DVECTOR\r\n    'time to increment the positions based on the applied forces\r\n    'during the specified timestep...\r\n    \r\n    For i = 1 To num_particles\r\n    \r\n        tmp = m_curp(i)\r\n        \r\n        m_curp(i).x = (m_curp(i).x * 2 - m_oldp(i).x) + (m_forc(i).x * m_timeStep)\r\n        m_curp(i).y = (m_curp(i).y * 2 - m_oldp(i).y) + (m_forc(i).y * m_timeStep)\r\n        m_curp(i).z = (m_curp(i).z * 2 - m_oldp(i).z) + (m_forc(i).z * m_timeStep)\r\n        \r\n        m_oldp(i) = tmp\r\n        \r\n    Next\r\n\r\nEnd Function\r\n\r\nPrivate Function SatisfyConstraints()\r\n    Dim delta As D3DVECTOR\r\n    Dim vscale As Double\r\n    Dim rl As Long\r\n    \r\n    'constrain the box to the ground..\r\n    For i = 1 To num_particles\r\n        If m_curp(i).y &lt; 0 Then\r\n            'we have hit the ground...\r\n            m_curp(i).y = 0\r\n            m_oldp(i).x = m_oldp(i).x + (m_curp(i).x - m_oldp(i).x) * 0.4\r\n            m_oldp(i).z = m_oldp(i).z + (m_curp(i).z - m_oldp(i).z) * 0.4\r\n        End If\r\n    Next\r\n        \r\n    \r\n    'constrain sticks based on there length\r\n    For i = 1 To num_join\r\n\r\n        D3DXVec3Subtract delta, m_curp(join_p2(i)), m_curp(join_p1(i))\r\n\r\n        rl = join_rl(i) * join_rl(i)\r\n        vscale = rl \/ (delta.x * delta.x + delta.y * delta.y + delta.z * delta.z + rl) - 0.5\r\n    \r\n        D3DXVec3Scale delta, delta, vscale\r\n\r\n        D3DXVec3Subtract m_curp(join_p1(i)), m_curp(join_p1(i)), delta\r\n\r\n        D3DXVec3Add m_curp(join_p2(i)), m_curp(join_p2(i)), delta\r\n    \r\n\r\n    Next\r\n    \r\n\r\n\r\n\r\nEnd Function\r\n\r\nPrivate Function AccumulateForces()\r\n    Dim i As Integer\r\n    'All particles are influenced by gravity\r\n    \r\n    For i = 0 To num_particles\r\n    \r\n        m_forc(i) = m_grav\r\n        \r\n    Next\r\n\r\nEnd Function\r\n<\/pre>\n<p>\t\t\t\t<\/font>Hopefully that\u2019s surprisingly little (I was certainly<br \/>\n\t\t\t\tsurprised).&nbsp; The main heartbeat is the Timestep function.&nbsp; It<br \/>\n\t\t\t\tcalls the tree helper functions in turn, AccumulateForces,<br \/>\n\t\t\t\tVerlet, SatisfyConstraints.&nbsp; <\/p>\n<p>\t\t\t\tThe Accumulate Forces function currently only adds gravity to<br \/>\n\t\t\t\teach of the points.&nbsp; Eventually this would be used to apply<br \/>\n\t\t\t\tother external forces like explosions or wind.&nbsp; The Verlet<br \/>\n\t\t\t\tfunction performs a simple progressive approximation of the new<br \/>\n\t\t\t\tposition.&nbsp; The position is found by taking the current position,<br \/>\n\t\t\t\tadding the change in position (current &#8211; old), and finally,<br \/>\n\t\t\t\tadding the distance due to the accumulated forces. <\/p>\n<p>\t\t\t\tThe last step is to satisfy any constraints that have been<br \/>\n\t\t\t\testablished.&nbsp; In this case if any points are falling through the<br \/>\n\t\t\t\tfloor (y &lt; 0).&nbsp; The other constraints are the \u2018sticks\u2019.&nbsp; These<br \/>\n\t\t\t\tconstraints are applied to ensure the distance between two<br \/>\n\t\t\t\tparticles is equal to the length of the stick.<\/p>\n<p>\t\t\t\tTo perform this distance manipulation I used the D3DX helper<br \/>\n\t\t\t\tlibraries which have a number of vector manipulation functions<br \/>\n\t\t\t\tbuilt in.&nbsp; In this case I check the length of the stick by<br \/>\n\t\t\t\tfinding the delta (difference) between the two points on the<br \/>\n\t\t\t\tstick.&nbsp; This distance may have x, y and z components.<\/p>\n<p>\t\t\t\tNow a restoration vector is made.&nbsp; This is a scaled version of<br \/>\n\t\t\t\tthe delta vector.&nbsp; The scale will attempt to restore the stick<br \/>\n\t\t\t\tto its constrained length.&nbsp; To keep things all equal half the<br \/>\n\t\t\t\trestoration is applied to both ends of the stick. <\/p>\n<p><h3>Bouncing Bits\u2026<\/h3>\n<p>\t\t\t\t<P><br \/>\n\t\t\t\t\t<a href=\"images\/tutorials\/ver1_bouncing_bits.zip\">Download sample code 96k<\/a><\/p>\n<p>\n\t\t\t\t<img decoding=\"async\" height=\"175\" src=\"images\/bugs\/image008.gif\" width=\"225\" border=\"0\"><\/p>\n<p>\n\t\t\t\tI can already imagine the strained attention spans, so as a<br \/>\n\t\t\t\tcompromise to my sanity (and yours) here are some bouncing bits.<\/p>\n<p>\t\t\t\tRemember that basic render loop. Well we are going to add some<br \/>\n\t\t\t\tguts to it. <font face=\"Courier New\" size=\"2\"><\/p>\n<pre>Private Sub Command1_Click()\r\n    Dim a%, cnt As Long\r\n    Dim v As CUSTOMVERTEX\r\n    Dim t As Long\r\n    \r\n    If m_run = False Then\r\n        m_run = True\r\n        t = GetTickCount - 10\r\n        Do\r\n        \r\n            m_timeStep = (GetTickCount() - t) \/ 10000\r\n            t = GetTickCount\r\n            \r\n            'do a physics engine tick\r\n            TimeStep\r\n            \r\n            'Start the Scene\r\n            g_dev.BeginScene\r\n            \r\n            'clear the buffer\r\n            D3DUtil_ClearAll QBColor(8)\r\n            \r\n            \r\n            g_dev.SetRenderState D3DRS_ZWRITEENABLE, 1\r\n            g_dev.SetRenderState D3DRS_ZENABLE, 1 'False\r\n            g_dev.SetRenderState D3DRS_ALPHABLENDENABLE, 1\r\n            \r\n            g_dev.SetRenderState D3DRS_SRCBLEND, D3DBLEND_ONE\r\n            g_dev.SetRenderState D3DRS_DESTBLEND, D3DBLEND_ONE\r\n            g_dev.SetTextureStageState 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE\r\n               \r\n            g_dev.SetRenderState D3DRS_POINTSPRITE_ENABLE, 1 'True\r\n            g_dev.SetRenderState D3DRS_POINTSCALE_ENABLE, 1\r\n            \r\n            g_dev.SetTexture 0, m_ParticleTexture\r\n            \r\n            g_dev.SetStreamSource 0, m_VertB, Len(v)\r\n            g_dev.SetVertexShader D3DFVF_COLORVERTEX\r\n            \r\n            \r\n            Dim DWFloat0 As Long\r\n            Dim DWFloat1 As Long\r\n            Dim DWFloatp08 As Long\r\n            DWFloat0 = FtoDW(0.1)\r\n            DWFloat1 = FtoDW(1)\r\n            DWFloatp08 = FtoDW(5)\r\n            ' Set the render states for using point sprites\r\n            g_dev.SetRenderState D3DRS_POINTSIZE, DWFloatp08\r\n            g_dev.SetRenderState D3DRS_POINTSIZE_MIN, DWFloat0\r\n            g_dev.SetRenderState D3DRS_POINTSCALE_A, DWFloat0\r\n            g_dev.SetRenderState D3DRS_POINTSCALE_B, DWFloat0\r\n            g_dev.SetRenderState D3DRS_POINTSCALE_C, DWFloat1\r\n            \r\n            ReDim m_Verts(m_MaxParticles * 2)\r\n            \r\n            \r\n            'Render the corners\r\n            cnt = 0\r\n            For a% = 0 To num_particles - 1\r\n                m_Verts(cnt).v = m_curp(a% + 1)\r\n                m_Verts(cnt).color = &amp;HFFFFFFFF\r\n                cnt = cnt + 1\r\n                If cnt = m_MaxParticles Then\r\n                    D3DVertexBuffer8SetData m_VertB, 0, Len(v) * cnt, 0, m_Verts(0)\r\n                    g_dev.DrawPrimitive D3DPT_POINTLIST, 0, cnt\r\n                    cnt = 0\r\n                End If\r\n            Next\r\n            D3DVertexBuffer8SetData m_VertB, 0, Len(v) * cnt, 0, m_Verts(0)\r\n            g_dev.DrawPrimitive D3DPT_POINTLIST, 0, cnt\r\n        \r\n            g_dev.SetRenderState D3DRS_POINTSPRITE_ENABLE, 0\r\n            g_dev.SetRenderState D3DRS_POINTSCALE_ENABLE, 0\r\n            g_dev.SetRenderState D3DRS_ALPHABLENDENABLE, 0\r\n        \r\n            'Render the edges\r\n            cnt = 0\r\n            For a% = 0 To num_join - 1\r\n                m_Verts(cnt * 2).v = m_curp(join_p1(a% + 1))\r\n                m_Verts(cnt * 2).color = &amp;HFFFFFFFF\r\n                m_Verts(cnt * 2 + 1).v = m_curp(join_p2(a% + 1))\r\n                m_Verts(cnt * 2 + 1).color = &amp;HFFFFFFFF\r\n                cnt = cnt + 1\r\n                If cnt = m_MaxParticles Then\r\n                    D3DVertexBuffer8SetData m_VertB, 0, Len(v) * cnt * 2, 0, m_Verts(0)\r\n                    g_dev.DrawPrimitive D3DPT_LINELIST, 0, cnt * 2\r\n                    cnt = 0\r\n                End If\r\n            Next\r\n            'whats left\r\n            D3DVertexBuffer8SetData m_VertB, 0, Len(v) * cnt * 2, 0, m_Verts(0)\r\n            g_dev.DrawPrimitive D3DPT_LINELIST, 0, cnt * 2\r\n            \r\n            \r\n            'End the scene\r\n            g_dev.EndScene\r\n            \r\n            'update the screen...\r\n            D3DUtil_PresentAll g_focushwnd\r\n            \r\n            \r\n            DoEvents\r\n        Loop Until m_run = False\r\n    End If\r\nEnd Sub\r\n<\/pre>\n<p>\t\t\t\t<\/font>Despite the slightly intimidating nature of the code,<br \/>\n\t\t\t\tit\u2019s really just 3 types of stuff going on.&nbsp; <\/p>\n<p style=\"MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt\">1)<font face=\"Arial\" size=\"2\">&nbsp;<br \/>\n\t\t\t\tCalls to our physics engine.<\/font><\/p>\n<p style=\"MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt\">2)<font face=\"Arial\" size=\"2\">&nbsp;<br \/>\n\t\t\t\tDX3D configuration code.&nbsp; This stuff sets up the render states,<br \/>\n\t\t\t\tand assigns textures to our points.<\/font><\/p>\n<p style=\"MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt\">3)<font face=\"Arial\" size=\"2\">&nbsp;<br \/>\n\t\t\t\tStuffing our vertex buffers full of bouncing points from our<br \/>\n\t\t\t\tphysics simulator, and then rendering the vertex buffer<br \/>\n\t\t\t\tprimitive.<\/font><\/p>\n<p>\n\t\t\t\tYou can try out the sample program to see how it all hangs<br \/>\n\t\t\t\ttogether.<\/p>\n<p>\t\t\t\tNot all graphics cards will display the point lists correctly,<br \/>\n\t\t\t\tbut these are little alpha globes used to mark the points at the<br \/>\n\t\t\t\tvertex of the objects.<\/p>\n<p>\t\t\t\tThe line list meanwhile should work fine, this is the sticks<br \/>\n\t\t\t\twhich hold the objects together.\t<\/p>\n<h3>Bounding Box<\/h3>\n<p>\n\t\t\t\t\t<a href=\"images\/tutorials\/ver2_boundingbox.zip\">Download sample code 98k<\/a> <\/p>\n<p>We have our objects, but it\u2019s not really much of a physics<br \/>\n\t\t\t\tsimulation because all our objects simply bounce through each<br \/>\n\t\t\t\tother.&nbsp; The only collisions are currently performed with the<br \/>\n\t\t\t\tfloor!<\/p>\n<p>\t\t\t\tThe collision detection technique I wanted to use is a plate<br \/>\n\t\t\t\tmethod.&nbsp; This essentially treats each face of an object as an<br \/>\n\t\t\t\tinfinite plate extending in all directions.&nbsp; Then by checking<br \/>\n\t\t\t\tfor a combination of collisions of plates between objects you<br \/>\n\t\t\t\tcan determine a collision.<\/p>\n<p>\t\t\t\tThis becomes more difficult as you try and manage edge or point<br \/>\n\t\t\t\tcollisions with a plate, and detecting exactly where the forces<br \/>\n\t\t\t\tshould be applied.<\/p>\n<p>\t\t\t\tHence rather than do maths, I have cheated in a very nasty quick<br \/>\n\t\t\t\tand dirty way!!!&nbsp; We are using my patented \u2018Bounding Box<br \/>\n\t\t\t\tcollisions for the maths impared\u2019 technique.<\/p>\n<p>&nbsp;<\/p>\n<p style=\"MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt\">1)<font face=\"Arial\" size=\"2\">&nbsp;<br \/>\n\t\t\t\tWe essentially figure out the biggest box that will enclose our<br \/>\n\t\t\t\tobject.<\/font><\/p>\n<p style=\"MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt\">2)<font face=\"Arial\" size=\"2\">&nbsp;<br \/>\n\t\t\t\tWe check if two bounding boxes touch each other.<\/font><\/p>\n<p style=\"MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt\">3)<font face=\"Arial\" size=\"2\">&nbsp;<br \/>\n\t\t\t\tWe figure out the centre of that box (our fake centre of mass)<\/font><\/p>\n<p style=\"MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt\">4)<font face=\"Arial\" size=\"2\">&nbsp;<br \/>\n\t\t\t\tWe calculate the distance between the centre of mass of the two<br \/>\n\t\t\t\tobjects.<\/font><\/p>\n<p style=\"MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt\">5)<font face=\"Arial\" size=\"2\">&nbsp;<br \/>\n\t\t\t\tWe repulse each other in opposite directions by a fraction of<br \/>\n\t\t\t\tthe distance (the closer they get, the more they are repulsed)<\/font><\/p>\n<p>\n\t\t\t\tSo like I say, not very scientific, but try out the demo and see<br \/>\n\t\t\t\tthe boxes \u2018collide\u2019.<\/p>\n<p>\t\t\t\tTo accommodate the bounding box, and the centre of mass, I added<br \/>\n\t\t\t\ta few new vectors to the body type.<br \/>\n\t\t\t\t<font face=\"Courier New\" size=\"2\"><\/p>\n<pre>Public Type body_type\r\n    Part_Min As Long\r\n    Part_Max As Long\r\n    Join_Max As Long\r\n    Join_Min As Long\r\n    \r\n    bound_min As D3DVECTOR\r\n    bound_max As D3DVECTOR\r\n    \r\n    centre_mass As D3DVECTOR\r\n    \r\n    mesh As Long\r\nEnd Type\r\n<\/pre>\n<p>\t\t\t\t<\/font>Now we add the Detect Collisions routine to the main<br \/>\n\t\t\t\tphysics timestep. <font face=\"Courier New\" size=\"2\"><\/p>\n<pre>Public Function TimeStep()\r\n    'this executed the requirements of the physics\r\n    'simulation for the current timestep\r\n\r\n    AccumulateForces\r\n    Verlet\r\n    DetectCollisions        \r\n    SatisfyConstraints    \r\nEnd Function\r\n<\/pre>\n<p>\t\t\t\t<\/font>And finally the actual code to detect collisions itself.&nbsp;<br \/>\n\t\t\t\tAs you can see it is fairly simple.&nbsp; Initially working out the<br \/>\n\t\t\t\tbounding box, and hence the centre of mass.<\/p>\n<p>\t\t\t\tThe routine checks for overlaps, and pushes each point in the<br \/>\n\t\t\t\tobject away from the other by half of the collision force.&nbsp; The<br \/>\n\t\t\t\tcollision force is estimated from the distance of their centre<br \/>\n\t\t\t\tof masses. <font face=\"Courier New\" size=\"2\"><\/p>\n<pre>Private Function DetectCollisions()\r\n    'collide with the ground...\r\n    Dim i As Long\r\n    Dim j As Long\r\n    Dim a As Long\r\n    Dim delta As D3DVECTOR\r\n    \r\n    For i = 1 To num_particles\r\n        If m_curp(i).y &lt; 0 Then\r\n            'we have hit the ground...\r\n            m_curp(i).y = 0\r\n            m_oldp(i).x = m_oldp(i).x + (m_curp(i).x - m_oldp(i).x) * 0.4\r\n            m_oldp(i).z = m_oldp(i).z + (m_curp(i).z - m_oldp(i).z) * 0.4\r\n        End If\r\n    Next\r\n    \r\n    'first precomputations\r\n    For i = 0 To num_body - 1\r\n        'bounding box\r\n        g_d3dx.ComputeBoundingBox m_curp(body(i).Part_Min), body(i).Part_Max - body(i).Part_Min, D3DFVF_NORMAL, _\r\nbody(i).bound_min, body(i).bound_max\r\n        'ridiculously cheap centre of mass\r\n        body(i).centre_mass.x = (body(i).bound_min.x + body(i).bound_max.x) \/ 2\r\n        body(i).centre_mass.y = (body(i).bound_min.y + body(i).bound_max.y) \/ 2\r\n        body(i).centre_mass.z = (body(i).bound_min.z + body(i).bound_max.z) \/ 2\r\n    Next\r\n    \r\n    'now check all the bodies if their bounding boxes overlap...\r\n    For i = 0 To num_body - 1\r\n        For j = i To num_body - 1\r\n            If (body(i).bound_min.x &gt; body(j).bound_min.x And body(i).bound_min.x &lt; body(j).bound_max.x) \r\n                Or (body(i).bound_max.x &gt; body(j).bound_min.x And body(i).bound_max.x &lt; body(j).bound_max.x) Then\r\n                If (body(i).bound_min.y &gt; body(j).bound_min.y And body(i).bound_min.y &lt; body(j).bound_max.y) \r\n                    Or (body(i).bound_max.y &gt; body(j).bound_min.y And body(i).bound_max.y &lt; body(j).bound_max.y) Then\r\n                    If (body(i).bound_min.z &gt; body(j).bound_min.z And body(i).bound_min.z &lt; body(j).bound_max.z) \r\n                       Or (body(i).bound_max.z &gt; body(j).bound_min.z And body(i).bound_max.z &lt; body(j).bound_max.z) Then\r\n                        'we have a bounding box collision, now examine in more detail...\r\n                        \r\n                        'super bogus for now...\r\n                        \r\n                        D3DXVec3Subtract delta, body(i).centre_mass, body(j).centre_mass\r\n                        D3DXVec3Scale delta, delta, 0.001\r\n                        'delta.x = 0.03 \/ delta.x\r\n                        'delta.y = 0.03 \/ delta.y\r\n                        'delta.z = 0.03 \/ delta.z\r\n                        \r\n                        For a = body(i).Part_Min To body(i).Part_Max\r\n                            'm_curp(a).x = m_curp(a).x - 5\r\n                            D3DXVec3Add m_curp(a), m_curp(a), delta\r\n                        Next\r\n                        For a = body(j).Part_Min To body(j).Part_Max\r\n                            'm_curp(a).x = m_curp(a).x - 5\r\n                            D3DXVec3Subtract m_curp(a), m_curp(a), delta\r\n                        Next\r\n                    End If\r\n                End If\r\n            End If\r\n        Next\r\n    Next\r\n\r\nEnd Function\r\n<\/pre>\n<p><\/font><\/p>\n<h3>Textured Bugs<\/h3>\n<p>\n\t<a href=\"images\/tutorials\/ver3_textured_bugs.zip\">Download sample code 437k<\/a><\/p>\n<p>\n\t\t\t\t<img decoding=\"async\" height=\"279\" src=\"images\/bugs\/image009.jpg\" width=\"400\" border=\"0\"><\/p>\n<p>\n\t\t\t\tWell physics (even cheap replicas) is pretty cool, but I feel<br \/>\n\t\t\t\tthe need for some bugs.&nbsp; Its time to take the mesh designed at<br \/>\n\t\t\t\tthe start of the tutorial &#8211; then get it bouncing along with the<br \/>\n\t\t\t\tboxes.<\/p>\n<p>\t\t\t\tIt sounds like a simple thing\u2026. and in the end it was simple,<br \/>\n\t\t\t\tbut I spent a lot of time reading text books and looking at<br \/>\n\t\t\t\tsource code before the answer became obvious.<\/p>\n<p>\t\t\t\tThe problem is to create a matrix that will orientate (in this<br \/>\n\t\t\t\tcase rotate) a mesh to line up with a 6 normalised vectors<br \/>\n\t\t\t\tdescribing the corners of a box.&nbsp; When I say normalised, this<br \/>\n\t\t\t\tmeans they are scaled to 1, and aligned with the origin so that<br \/>\n\t\t\t\ttranslation and scaling to not mess up our maths.<\/p>\n<p>\t\t\t\tAfter going through all sorts of mathematical torture it became<br \/>\n\t\t\t\tevident, slightly unbelievably, that it is exactly these vector<br \/>\n\t\t\t\tvalues that make up the matrix\u2026 as this is basically the proof<br \/>\n\t\t\t\tof a rotation matrix.<\/p>\n<p>\t\t\t\tIf we consider only three points of the six, which is enough to<br \/>\n\t\t\t\tform an axis, you can see from this diagram how they fit into<br \/>\n\t\t\t\tthe matrix.<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" height=\"226\" src=\"images\/bugs\/image010.png\" width=\"554\" border=\"0\"><\/p>\n<p>\n\t\t\t\tThe end result is a rotation matrix.&nbsp; We then add the<br \/>\n\t\t\t\ttranslation and scaling back to the matrix, and \u2018bingo\u2019 we can<br \/>\n\t\t\t\treposition our mesh aligned with the points in our physics<br \/>\n\t\t\t\tengine. <font face=\"Courier New\" size=\"2\"><\/p>\n<pre>For i = 0 To num_body - 1\r\n                If body(i).Part_Max - body(i).Part_Min = 7 Then\r\n                                       \r\n                    p1 = m_curp(body(i).Part_Min)\r\n                    p2 = m_curp(body(i).Part_Min + 1)\r\n                    p4 = m_curp(body(i).Part_Min + 3)\r\n                    p5 = m_curp(body(i).Part_Min + 4)\r\n                    \r\n                    D3DXVec3Subtract vx, p4, p1\r\n                    D3DXVec3Subtract vy, p2, p1\r\n                    D3DXVec3Subtract vz, p5, p1\r\n                    \r\n                    D3DXVec3Normalize vx, vx\r\n                    D3DXVec3Normalize vy, vy\r\n                    D3DXVec3Normalize vz, vz\r\n                  \r\n                  \r\n                    m3.m11 = vx.x\r\n                    m3.m12 = vx.y\r\n                    m3.m13 = vx.z\r\n                    m3.m21 = vy.x\r\n                    m3.m22 = vy.y\r\n                    m3.m23 = vy.z\r\n                    m3.m31 = vz.x\r\n                    m3.m32 = vz.y\r\n                    m3.m33 = vz.z\r\n                    m3.m44 = 1\r\n                                       \r\n                    D3DXMatrixTranslation m2, m_curp(body(i).Part_Min).x, \r\n                             m_curp(body(i).Part_Min).y, m_curp(body(i).Part_Min).z\r\n                    \r\n                    D3DXMatrixScaling m, (join_rl(body(i).Join_Min + 1)) * 0.013, \r\n                           (join_rl(body(i).Join_Min)) * 0.04, (join_rl(body(i).Join_Min + 9)) * 0.015\r\n                                        \r\n                    D3DXMatrixMultiply m, m, m3\r\n                    D3DXMatrixMultiply m, m, m2\r\n                    \r\n                    m_frame.SetMatrix m\r\n                    m_frame.Render g_dev\r\n                End If\r\n            Next\r\n<\/pre>\n<p>\t\t\t\t<\/font>The next elements of interest is the code which actually<br \/>\n\t\t\t\thandles the mesh.&nbsp; By using the existing Microsoft mesh class<br \/>\n\t\t\t\tprovided it is reasonably easy.<br \/>\n\t\t\t\t<font face=\"Courier New\" size=\"2\"><\/p>\n<pre>  'load our mesh...\r\n    Set m_frame = New CD3DFrame\r\n    m_frame.InitFromFile g_dev, App.path + &quot;\\bug.x&quot;, Nothing, Nothing\r\n<\/pre>\n<p>\t\t\t\t<\/font>This loads a mesh into a frame, then the calls in the<br \/>\n\t\t\t\tmatrix mesh code above (m_frame.SetMatrix m&nbsp;&nbsp; and&nbsp;&nbsp;<br \/>\n\t\t\t\tm_frame.Render g_dev) actually do the alignment and rendering.<\/p>\n<p>\t\t\t\tTo get some camera control I have also added a quick bit of<br \/>\n\t\t\t\tcamera manipulation.&nbsp; You can see this here;<br \/>\n\t\t\t\t<font face=\"Courier New\" size=\"2\"><\/p>\n<pre>Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)\r\n    dwn% = True\r\n    mx = x\r\n    my = y\r\nEnd Sub\r\n\r\nPrivate Sub Picture1_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)\r\n    If dwn% Then\r\n         ox = ox - (mx - x)\r\n         oy = oy - (my - y)\r\n         mx = x\r\n         my = y\r\n         D3DUtil_SetupCamera vec3(0, 200, (oy)), vec3((ox), 0, 0), vec3(0, 1, 0)\r\n    End If\r\nEnd Sub\r\n\r\nPrivate Sub Picture1_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)\r\n    dwn% = False\r\nEnd Sub\r\n<\/pre>\n<p>\t\t\t\t<\/font><\/p>\n<h3>Shadows<\/h3>\n<p>\n\t\t<A href=\"images\/tutorials\/ver4_shadows.zip\">Download sample code 437k<\/a><\/p>\n<p>\n\t\t\t\t<img decoding=\"async\" height=\"364\" src=\"images\/bugs\/image012.jpg\" width=\"400\" border=\"0\"><\/p>\n<p>\n\t\t\t\tWell things are hotting up. We now have bouncing, colliding<br \/>\n\t\t\t\tbugs.&nbsp; But with our overhead light, it gets hard to see exactly<br \/>\n\t\t\t\twhere our bugs are.&nbsp; The idea of adding a shadow allows the user<br \/>\n\t\t\t\tto see intuitively the position of the bug when it is off the<br \/>\n\t\t\t\tground.<\/p>\n<p>\t\t\t\tWe essentially cast a spherical shadow from the bugs centre of<br \/>\n\t\t\t\tmass down to the floor.&nbsp; The size and intensity of the shadow<br \/>\n\t\t\t\twill vary in proximity to the floor.<br \/>\n\t\t\t\t<font face=\"Courier New\" size=\"2\"><\/p>\n<pre>'draw a shadow..\r\n            Dim sz As Double\r\n            Dim cl As Long\r\n            ReDim m_Verts(num_body * 6)\r\n            For i = 0 To num_body - 1\r\n                If body(i).Part_Max - body(i).Part_Min = 7 Then 'the primitive is a cube...\r\n                    sz = join_rl(body(i).Join_Min + 1) \/ Log(body(i).centre_mass.y + 0.01)\r\n                    cl = body(i).centre_mass.y\r\n                    If cl &lt; 100 Then cl = 100\r\n                    If cl &gt; 255 Then cl = 255\r\n                    cl = RGB(cl, cl, cl)\r\n                    'project the surface down the y axis...\r\n                    m_Verts(i * 6 + 0).v.x = body(i).centre_mass.x - sz\r\n                    m_Verts(i * 6 + 0).v.z = body(i).centre_mass.z - sz\r\n                    m_Verts(i * 6 + 0).v.y = 1\r\n                    m_Verts(i * 6 + 0).n.y = 1\r\n                    m_Verts(i * 6 + 0).tu = 0\r\n                    m_Verts(i * 6 + 0).tv = 0\r\n                    m_Verts(i * 6 + 0).color = cl\r\n\r\n                    m_Verts(i * 6 + 1).v.x = body(i).centre_mass.x - sz\r\n                    m_Verts(i * 6 + 1).v.z = body(i).centre_mass.z + sz\r\n                    m_Verts(i * 6 + 1).v.y = 1\r\n                    m_Verts(i * 6 + 1).n.y = 1\r\n                    m_Verts(i * 6 + 1).tu = 0\r\n                    m_Verts(i * 6 + 1).tv = 1\r\n                    m_Verts(i * 6 + 1).color = cl\r\n\r\n                    m_Verts(i * 6 + 2).v.x = body(i).centre_mass.x + sz\r\n                    m_Verts(i * 6 + 2).v.z = body(i).centre_mass.z + sz\r\n                    m_Verts(i * 6 + 2).v.y = 1\r\n                    m_Verts(i * 6 + 2).n.y = 1\r\n                    m_Verts(i * 6 + 2).tu = 1\r\n                    m_Verts(i * 6 + 2).tv = 1\r\n                    m_Verts(i * 6 + 2).color = cl\r\n\r\n                    m_Verts(i * 6 + 3).v.x = body(i).centre_mass.x - sz\r\n                    m_Verts(i * 6 + 3).v.z = body(i).centre_mass.z - sz\r\n                    m_Verts(i * 6 + 3).v.y = 1\r\n                    m_Verts(i * 6 + 3).n.y = 1\r\n                    m_Verts(i * 6 + 3).tu = 0\r\n                    m_Verts(i * 6 + 3).tv = 0\r\n                    m_Verts(i * 6 + 3).color = cl\r\n\r\n                    m_Verts(i * 6 + 4).v.x = body(i).centre_mass.x + sz\r\n                    m_Verts(i * 6 + 4).v.z = body(i).centre_mass.z + sz\r\n                    m_Verts(i * 6 + 4).v.y = 1\r\n                    m_Verts(i * 6 + 4).n.y = 1\r\n                    m_Verts(i * 6 + 4).tu = 1\r\n                    m_Verts(i * 6 + 4).tv = 1\r\n                    m_Verts(i * 6 + 4).color = cl\r\n\r\n                    m_Verts(i * 6 + 5).v.x = body(i).centre_mass.x + sz\r\n                    m_Verts(i * 6 + 5).v.z = body(i).centre_mass.z - sz\r\n                    m_Verts(i * 6 + 5).v.y = 1\r\n                    m_Verts(i * 6 + 5).n.y = 1\r\n                    m_Verts(i * 6 + 5).tu = 1\r\n                    m_Verts(i * 6 + 5).tv = 0\r\n                    m_Verts(i * 6 + 5).color = cl\r\n                End If\r\n            Next\r\n            \r\n            g_dev.SetTexture 0, m_ShadowTexture\r\n            g_dev.SetRenderState D3DRS_ALPHABLENDENABLE, 1\r\n            g_dev.SetTextureStageState 0, D3DTSS_ALPHAOP, D3DTOP_SUBTRACT\r\n            g_dev.SetRenderState D3DRS_SRCBLEND, D3DBLEND_SRCALPHA\r\n            g_dev.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA\r\n            g_dev.SetVertexShader D3DFVF_COLORVERTEX\r\n            g_dev.SetStreamSource 0, m_VertB, Len(v)\r\n            D3DVertexBuffer8SetData m_VertB, 0, Len(v) * (num_body) * 6, 0, m_Verts(0)\r\n            g_dev.DrawPrimitive D3DPT_TRIANGLELIST, 0, (num_body) * 2\r\n<\/pre>\n<p>\t\t\t\t<\/font>This code sets up the \u2018quad\u2019 that is used to draw the<br \/>\n\t\t\t\tshadow.&nbsp; A quad is simply two triangles that are next to each<br \/>\n\t\t\t\tother to form a square (4 corners = quad).<\/p>\n<p>\t\t\t\tThe blend colour intensity and size of the quad is determined by<br \/>\n\t\t\t\tthe proximity to the ground.<\/p>\n<h3>Driving<\/h3>\n<p>\n\t<A href=\"images\/tutorials\/ver5_driving.zip\">Download sample code 442k<\/a><br \/>\n<P><br \/>\n\t\t\t\tIt\u2019s time to get control of our bugs.&nbsp; There is no fun in a<br \/>\n\t\t\t\ttotally passive simulation.&nbsp; We want to drive our bugs around<br \/>\n\t\t\t\tour scene to test out our collision algorithms.<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" height=\"360\" src=\"images\/bugs\/image013.jpg\" width=\"400\" border=\"0\"><\/p>\n<p>\n\t\t\t\tTo enable us to trap the state of multiple keys, I use a key<br \/>\n\t\t\t\tarray state trick.&nbsp; This works like this;<br \/>\n\t\t\t\t<font face=\"Courier New\" size=\"2\"><\/p>\n<prePrivate Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)\r\n    keyarray(KeyCode) = 1\r\nEnd Sub\r\n\r\nPrivate Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)\r\n    keyarray(KeyCode) = 0\r\nEnd Subb\r\n<\/pre>\n<p>\t\t\t\t<\/font>For any key we can now check if it is currently held<br \/>\n\t\t\t\tdown.&nbsp; The code that the bug actually responds to is in the<br \/>\n\t\t\t\tcheck_keys routines.&nbsp; It looks something like this;<br \/>\n\t\t\t\t<font face=\"Courier New\" size=\"2\"><\/p>\n<pre>Private Sub check_keys()\r\n    Dim v As D3DVECTOR\r\n    Dim v2 As D3DVECTOR\r\n    Dim m As D3DMATRIX\r\n    Dim k As Long\r\n        If keyarray(vbKeyLeft) Then\r\n        D3DXMatrixIdentity m\r\n        D3DXMatrixRotationY m, -10 * m_timeStep\r\n        For k = 1 To 88\r\n            D3DXVec3Subtract v, m_curp(k), body(0).centre_mass\r\n            'v is now relative to the centre of the box\r\n            D3DXVec3TransformNormal v, v, m\r\n            'now put it back\r\n            D3DXVec3Add m_curp(k), v, body(0).centre_mass\r\n            'update the old particle position\r\n            m_oldp(k).x = m_curp(k).x\r\n            m_oldp(k).z = m_curp(k).z\r\n        Next\r\n    End If\r\n    If keyarray(vbKeyRight) Then\r\n        D3DXMatrixIdentity m\r\n        D3DXMatrixRotationY m, 10 * m_timeStep\r\n        For k = 1 To 8\r\n            D3DXVec3Subtract v, m_curp(k), body(0).centre_mass\r\n            'v is now relative to the centre of the box\r\n            D3DXVec3TransformNormal v, v, m\r\n            'now put it back\r\n            D3DXVec3Add m_curp(k), v, body(0).centre_mass\r\n            m_oldp(k) = m_curp(k)\r\n        Next\r\n    End If\r\n    If keyarray(vbKeyUp) Then\r\n        D3DXVec3Subtract v, m_curp(5), m_curp(1)\r\n        D3DXVec3Scale v2, v, -19.9 * m_timeStep\r\n        D3DXVec3Scale v, v, -20 * m_timeStep\r\n        v.y = 0\r\n        v2.y = 0\r\n        If m_curp(1).y &gt; m_curp(2).y Then\r\n            'whoops upside down..\r\n            m_curp(1).y = m_curp(1).y + (m_curp(1).y - m_curp(2).y) \/ 50\r\n            m_curp(4).y = m_curp(4).y + (m_curp(1).y - m_curp(2).y) \/ 50\r\n        End If\r\n        For k = 1 To 8\r\n            D3DXVec3Add m_curp(k), m_curp(k), v\r\n            D3DXVec3Add m_oldp(k), m_oldp(k), v2\r\n        Next\r\n    End If\r\n    If keyarray(vbKeyDown) Then\r\n        D3DXVec3Subtract v, m_curp(5), m_curp(1)\r\n        D3DXVec3Scale v2, v, 19.9 * m_timeStep\r\n        D3DXVec3Scale v, v, 20 * m_timeStep\r\n        v.y = 0\r\n        v2.y = 0\r\n        For k = 1 To 8\r\n            D3DXVec3Add m_curp(k), m_curp(k), v\r\n            D3DXVec3Add m_oldp(k), m_oldp(k), v2\r\n        Next\r\n    End If\r\nEnd Sub\r\n<\/pre>\n<p>\t\t\t\t<\/font>The end result is that the bug moves forward in the<br \/>\n\t\t\t\tdirection the bug is pointing.&nbsp; Pressing the right or left keys<br \/>\n\t\t\t\twill rotate the bug slightly in that direction.<\/p>\n<h3>Camera<\/h3>\n<p>\n\t<a href=\"images\/tutorials\/ver6_camera.zip\">Download sample code 442k<\/a><\/p>\n<p>\n\t\t\t\tHmm, I was busy trying to knock another bug off the map, and I<br \/>\n\t\t\t\tran off-screen.&nbsp; It\u2019s hard to control your bug when you can\u2019t<br \/>\n\t\t\t\tsee it. &nbsp;Definitely time to add camera control.<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" height=\"528\" src=\"images\/bugs\/image014.jpg\" width=\"304\" border=\"0\"><\/p>\n<p>\n\t\t\t\tAs you can see from the picture, the bug stays on screen, as the<br \/>\n\t\t\t\trest of the scene moves around. <br \/>\n\t\t\t\tIn-fact we ended up with 3 camera modes.&nbsp; This one is<br \/>\n\t\t\t\tcamera_mode 2, the far away camera that pans to follow our bug.&nbsp;<br \/>\n\t\t\t\tThis is possibly the simplist.&nbsp; We calculate the vector between<br \/>\n\t\t\t\tthe distant camera and the bug, and then point the camera in<br \/>\n\t\t\t\tthat direction.<\/p>\n<p>\t\t\t\tIn mode 1 we move the camera around to follow the bug.&nbsp; It does<br \/>\n\t\t\t\tthis with a slight delay.&nbsp; This way the camera essentially drags<br \/>\n\t\t\t\talong behind the bug.<\/p>\n<p>\t\t\t\tFinally in mode 0 (first bug mode) the camera is always mounted<br \/>\n\t\t\t\ton the front of our bugs antennae.&nbsp; The hardest part of this was<br \/>\n\t\t\t\tfinding a small enough camera.<\/p>\n<p>\t\t\t\tSource code; <font face=\"Courier New\" size=\"2\"><\/p>\n<pre>   'position the camera\r\n            If camera_mode = 0 Then\r\n                'first bug mode...\r\n                D3DXVec3Subtract vec, m_curp(4), m_curp(1)\r\n                D3DXVec3Scale vec, vec, 0.5\r\n                D3DXVec3Add vec_to, m_curp(6), vec\r\n                D3DXVec3Add vec_from, m_curp(2), vec\r\n                D3DUtil_SetupCamera vec_to, vec_from, vec3(0, 1, 0)\r\n            ElseIf camera_mode = 1 Then\r\n                '3rd bug mode\r\n                D3DXVec3Subtract vec, vec_from, body(0).centre_mass\r\n                D3DXVec3Scale vec, vec, 0.25\r\n                D3DXVec3Subtract vec_to, vec_from, vec\r\n                \r\n                D3DUtil_SetupCamera vec_from, vec_to, vec3(0, 1, 0)\r\n                \r\n                'animate the vec_from...\r\n                D3DXVec3Normalize vec, vec\r\n                D3DXVec3Scale vec, vec, 60\r\n                D3DXVec3Add vec, body(0).centre_mass, vec\r\n                vec.y = vec.y + 25\r\n                \r\n                D3DXVec3Lerp vec_from, vec_from, vec, 0.02\r\n            ElseIf camera_mode = 2 Then\r\n                'far away camera...\r\n                vec_from = vec3(0, 120, -400)\r\n                \r\n                D3DXVec3Subtract vec, vec_from, body(0).centre_mass\r\n                D3DXVec3Scale vec, vec, 0.25\r\n                D3DXVec3Subtract vec_to, vec_from, vec\r\n                \r\n                D3DUtil_SetupCamera vec_from, vec_to, vec3(0, 1, 0)\r\n            End If\r\n<\/pre>\n<p>\t\t\t\t<\/font><\/p>\n<h3>Animation<\/h3>\n<p>\n\t<a href=\"images\/tutorials\/ver7_animation.zip\">Download sample code 442k<\/a><\/p>\n<p>\n\t\t\t\tPotentially the most disconcerting part of the current tutorial<br \/>\n\t\t\t\tis the way the bugs are simply gliding along on the concrete<br \/>\n\t\t\t\tfloor.&nbsp; It\u2019s time to introduce some animation.<\/p>\n<p>\t\t\t\tI originally built and exported some basic keyframe animation<br \/>\n\t\t\t\tfor the legs of the bugs.<\/p>\n<p>\t\t\t\tTo reproduce this animation in VB I found a few problems with<br \/>\n\t\t\t\tsome of the class libraries provided, but it all worked out in<br \/>\n\t\t\t\tthe end.<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" height=\"171\" src=\"images\/bugs\/image015.jpg\" width=\"252\" border=\"0\"><\/p>\n<p>\n\t\t\t\tThe end result is we load the animation into the frame like so;<br \/>\n\t\t\t\t<font face=\"Courier New\" size=\"2\"><\/p>\n<pre>'load our mesh...\r\n    Set m_frame = New CD3DFrame\r\n    Set Animation = New CD3DAnimation\r\n    m_frame.InitFromFile g_dev, App.path + &quot;\\bug.x&quot;, Nothing, Animation\r\n<\/pre>\n<p>\t\t\t\t<\/font>Then we set which animation to use like so;<br \/>\n\t\t\t\t<font face=\"Courier New\" size=\"2\"><\/p>\n<pre>Animation.SetTime Int(anim) - 0.00005\r\n<\/pre>\n<p>\t\t\t\t<\/font>The end result is by increasing the animation counter we<br \/>\n\t\t\t\tcan proceed to cycle through our animation, and the legs wiggle.<\/p>\n<h3>Final<\/h3>\n<p>\n\t<a href=\"images\/tutorials\/ver9_final.zip\">Download final sample code 559k<\/a><\/p>\n<p>\n\t\t\t\tWell here we go, the final application.&nbsp; I decided to add a nice<br \/>\n\t\t\t\t\u2018help screen\u2019 billboard with a bit of alpha-blending to make it<br \/>\n\t\t\t\tlook interesting.&nbsp; (notice how the bug in the bottom left shows<br \/>\n\t\t\t\tthrough)<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" height=\"308\" src=\"images\/bugs\/image016.jpg\" width=\"427\" border=\"0\"><\/p>\n<p>\n\t\t\t\tThis is drawn using another quad.&nbsp;&nbsp; I should probably put this<br \/>\n\t\t\t\tinto a helper function to save wasting lines of code, but here<br \/>\n\t\t\t\tit is anyway : ) <font face=\"Courier New\" size=\"2\"><\/p>\n<pre>'draw the help...\r\n            If m_help Then\r\n                g_dev.SetTexture 0, m_HelpTexture\r\n                \r\n                D3DXMatrixLookAtLH g_viewMatrix, vec3(0, 12, -30), \r\n                  vec3(Cos(t \/ 1000), 10 + Sin(t \/ 1000), 0), vec3(0, 1, 0)\r\n                g_dev.SetTransform D3DTS_VIEW, g_viewMatrix\r\n                \r\n                m_Verts(0).v.x = 10\r\n                m_Verts(0).v.z = -5\r\n                m_Verts(0).v.y = 0\r\n                m_Verts(0).n.z = 1\r\n                m_Verts(0).tu = 1\r\n                m_Verts(0).tv = 1\r\n                m_Verts(0).color = RGB(255, 255, 255)\r\n                \r\n                m_Verts(1).v.x = -10\r\n                m_Verts(1).v.z = -5\r\n                m_Verts(1).v.y = 0\r\n                m_Verts(1).n.z = 1\r\n                m_Verts(1).tu = 0\r\n                m_Verts(1).tv = 1\r\n                m_Verts(1).color = RGB(255, 255, 255)\r\n                \r\n                m_Verts(2).v.x = 10\r\n                m_Verts(2).v.z = -5\r\n                m_Verts(2).v.y = 20\r\n                m_Verts(2).n.z = 1\r\n                m_Verts(2).tu = 1\r\n                m_Verts(2).tv = 0\r\n                m_Verts(2).color = RGB(255, 255, 255)\r\n                \r\n                m_Verts(3).v.x = 10\r\n                m_Verts(3).v.z = -5\r\n                m_Verts(3).v.y = 20\r\n                m_Verts(3).n.z = 1\r\n                m_Verts(3).tu = 1\r\n                m_Verts(3).tv = 0\r\n                m_Verts(3).color = RGB(255, 255, 255)\r\n                \r\n                m_Verts(4).v.x = -10\r\n                m_Verts(4).v.z = -5\r\n                m_Verts(4).v.y = 0\r\n                m_Verts(4).n.z = 1\r\n                m_Verts(4).tu = 0\r\n                m_Verts(4).tv = 1\r\n                m_Verts(4).color = RGB(255, 255, 255)\r\n                \r\n                m_Verts(5).v.x = -10\r\n                m_Verts(5).v.z = -5\r\n                m_Verts(5).v.y = 20\r\n                m_Verts(5).n.z = 1\r\n                m_Verts(5).tu = 0\r\n                m_Verts(5).tv = 0\r\n                m_Verts(5).color = RGB(255, 255, 255)\r\n                \r\n                \r\n                g_dev.SetRenderState D3DRS_ALPHABLENDENABLE, 1\r\n                g_dev.SetTextureStageState 0, D3DTSS_ALPHAOP, D3DTOP_SUBTRACT\r\n                g_dev.SetRenderState D3DRS_SRCBLEND, D3DBLEND_SRCALPHA\r\n                g_dev.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA\r\n                g_dev.SetVertexShader D3DFVF_COLORVERTEX\r\n                g_dev.SetStreamSource 0, m_VertB, Len(v)\r\n                D3DVertexBuffer8SetData m_VertB, 0, Len(v) * 6, 0, m_Verts(0)\r\n                g_dev.DrawPrimitive D3DPT_TRIANGLELIST, 0, 2\r\n            End If\r\n<\/pre>\n<p>\t\t\t\t<\/font><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Back to the future for a tutorial from 2002 using VB6 and DirectX 8.0!!! Download final sample code 559k The [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[40],"tags":[24,25,31,32,16],"class_list":["post-278","post","type-post","status-publish","format-standard","hentry","category-umaijn","tag-physics","tag-verlet","tag-bugs","tag-vb","tag-3d"],"_links":{"self":[{"href":"https:\/\/www.davidbrebner.com\/index.php?rest_route=\/wp\/v2\/posts\/278","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.davidbrebner.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.davidbrebner.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.davidbrebner.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.davidbrebner.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=278"}],"version-history":[{"count":3,"href":"https:\/\/www.davidbrebner.com\/index.php?rest_route=\/wp\/v2\/posts\/278\/revisions"}],"predecessor-version":[{"id":495,"href":"https:\/\/www.davidbrebner.com\/index.php?rest_route=\/wp\/v2\/posts\/278\/revisions\/495"}],"wp:attachment":[{"href":"https:\/\/www.davidbrebner.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=278"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.davidbrebner.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=278"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.davidbrebner.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=278"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}