now with mesh cages AND player meshes that match collision cage orientation.
NOTE: requires car.x file located in Samples\Blitz 3D Samples\mak\driver. if the code crashes move car.x into a directory with the code and modify the loadmesh statement.
NOTE: requires car.x file located in Samples\Blitz 3D Samples\mak\driver. if the code crashes move car.x into a directory with the code and modify the loadmesh statement.
; 3D Verlet Functions ; from Thomas Jakobsen's "Advanced Character Physics" ; www.gamasutra.com/resource_guide/20030121/jacobson_01.shtml ; Adapted for Blitz3D by Chris "Miracle" Casey, May 6 2003 ; ; Added polymesh "cage" around verlet group and made constraint distance auto-calculating - Dave Cornish ; Need to make polymesh cage a collideable entity. I have had some minor success with this but its very complicated ; so it is left OUT of this version. ; Added player mesh and orient that mesh to the collision mesh Graphics3D height,width,0,1 Const height=640 Const width=480 Const ACTIVE=1 Const radius#=.33333 Const size#=1.5 Const ITERATIONS = 5 ; How many loops through the "relaxation" routine, Lower = speed up / lose accuracy Global fTimeStep# Global vGrav.Vector = Vector(0.0,4,0.0) ; Gravity Global Temp.Vector=Vector() Global vTemp1.Vector = Vector(0,0,0) ; Some temporary vectors for calculations Global vTemp2.Vector = Vector(0,0,0) Global tol# = 0.001 Type Vector Field x# Field y# Field z# End Type Type VerletPack ; Contains everything we need for basic physics Field m.Vector ; Current position Field old.Vector ; Last position Field a.Vector ; Accumulated forces Field radius# ; Collision radius from center Field mass# ; Arbitrary mass unit Field entity ; Placeholder for the 3D sphere Field obj ; Which construct is this verlet a part of? Field vertex ; vertex assigned to verlet Field surface ; surface id from cube type Field mesh ; mesh id from cube type End Type Type Constraint ; Two verlets connected by a mutual spring Field v1.VerletPack Field v2.VerletPack Field d# ; Distance between verlets End Type Type cube Field v.VerletPack[8] Field player ; Player mesh Field center.VerletPack ; Used to pisition player mesh Field x1.VerletPack ; Used to orient player mesh to collision mesh/verlets Field x2.VerletPack Field z1.VerletPack Field z2.VerletPack Field X_vec# ; Junk for calculations Field Y_vec# Field Z_vec# End Type ClearTextureFilters SetBuffer BackBuffer() Collisions ACTIVE,ACTIVE,2,1 MoveMouse width/2,height/2 lgt = CreateLight() cam = CreateCamera() flr = CreateCube() ScaleEntity flr,20,20,20 PositionEntity flr,0,10,0 EntityType flr,ACTIVE grid_tex=CreateTexture( 256,256,1+4+8) SetBuffer TextureBuffer( grid_tex ) ScaleTexture grid_tex,.2,.2 Color 255,255,255:Rect 0,0,256,256,False grid_tex2=CreateTexture( 32,32,1) SetBuffer TextureBuffer( grid_tex2 ) ScaleTexture grid_tex2,100,100 Color 0,0,60:Rect 0,0,32,32,False EntityTexture flr,grid_tex,0,1 EntityTexture flr,grid_tex2,0,0 TextureBlend grid_tex,3 EntityFX flr,1 FlipMesh flr SetBuffer BackBuffer() For m = 1 To 10 ; Let's make some cubes! xa# = 0 xb# = m*5 +5 xc# = 0 cc.cube = New cube mesh=CreateMesh() surface=CreateSurface(mesh) cc\player=LoadMesh( "..\Samples\Blitz 3D Samples\mak\driver\car.x" ) ; this can be loaded in the "Samples\Blitz 3D Samples\mak\driver" FitMesh cc\player,-size,-size,-size,size*2,size*2,size*2 ; Yes, all the below is necessary to create a stable 9-verlet "cube" ... a.VerletPack = Verlet(xa - size, xb - size, xc - size, radius, 1.0, m, 0, 0, 0,surface,mesh,True) b.VerletPack = Verlet(xa + size, xb - size, xc - size, radius, 1.0, m, 0, 0, 0,surface,mesh,True) c.VerletPack = Verlet(xa + size, xb + size, xc - size, radius, 1.0, m, 255, 0, 0,surface,mesh,True) d.VerletPack = Verlet(xa - size, xb + size, xc - size, radius, 1.0, m, 0, 255, 0,surface,mesh,True) e.VerletPack = Verlet(xa - size, xb - size, xc + size, radius, 1.0, m, 0, 0, 0,surface,mesh,True) f.VerletPack = Verlet(xa + size, xb - size, xc + size, radius, 1.0, m, 0, 0, 0,surface,mesh,True) g.VerletPack = Verlet(xa + size, xb + size, xc + size, radius, 1.0, m, 0, 0, 255,surface,mesh,True) h.VerletPack = Verlet(xa - size, xb + size, xc + size, radius, 1.0, m, 0, 0, 0,surface,mesh,True) i.VerletPack = Verlet(xa, xb, xc,size, 1.0, m, 255, 255, 255,surface,mesh,True) AddTriangle(surface,0,2,1) AddTriangle(surface,0,3,2) AddTriangle(surface,0,1,5) AddTriangle(surface,0,5,4) AddTriangle(surface,0,4,7) AddTriangle(surface,0,7,3) AddTriangle(surface,6,1,2) AddTriangle(surface,6,2,3) AddTriangle(surface,6,5,1) AddTriangle(surface,6,4,5) AddTriangle(surface,6,7,4) AddTriangle(surface,6,3,7) UpdateNormals mesh EntityType mesh,0 EntityColor mesh,255,0,0 EntityAlpha mesh,0 ; Edges - distance 1.0 Constraint2(a,b) Constraint2(b,c) Constraint2(a,d) Constraint2(c,d) Constraint2(e,f) Constraint2(f,g) Constraint2(e,h) Constraint2(g,h) Constraint2(a,e) Constraint2(b,f) Constraint2(c,g) Constraint2(d,h) ; Cross-faces - distance ~Sqr(2.0) Constraint2(a,c) Constraint2(b,d) Constraint2(e,g) Constraint2(f,h) Constraint2(a,f) Constraint2(a,h) Constraint2(b,e) Constraint2(b,g) Constraint2(c,f) Constraint2(c,h) Constraint2(d,e) Constraint2(d,g) ; Diagonals - distance ~Sqr(3.0) Constraint2(a,g) Constraint2(b,h) Constraint2(c,e) Constraint2(d,f) ; Constraining the center sphere - distance ~0.5 * Sqr(3.0) Constraint2(a,i) Constraint2(b,i) Constraint2(c,i) Constraint2(d,i) Constraint2(e,i) Constraint2(f,i) Constraint2(g,i) Constraint2(h,i) cc\v[0] = i cc\v[1] = a cc\v[2] = b cc\v[3] = c cc\v[4] = d cc\v[5] = e cc\v[6] = f cc\v[7] = g cc\v[8] = h ; Set up variables used for player mesh cc\center=i cc\x1=c cc\x2=d cc\z1=g cc\z2=c Next ;********* functions defined ******************************************** Function TimeStep() ; The main loop AccumulateForces() DoVerlet() SatisfyConstraints2() End Function Function AccumulateForces() ; As of right now, we only accumulate gravity For v.VerletPack = Each VerletPack CloneVector(v\a,vGrav) Next End Function Function DoVerlet() For v.VerletPack = Each VerletPack CloneVector(vTemp1,v\m) MulVecScalar(vTemp2,v\a,fTimeStep * fTimeStep) ; a * timestep * timestep AddVector2(v\old,vTemp2) ; old = old + a * ts * ts SubVector2(v\m,v\old) ; m = m - old + a * ts * ts AddVector2(v\m,vTemp1) ; m += m - old + a * ts * ts CloneVector(v\old,vTemp1) Next End Function Function SatisfyConstraints2() For n = 1 To ITERATIONS For c.Constraint = Each Constraint SetDistance(c\v1,c\v2,c\d) Next For cc.cube = Each cube bing = 0 q.cube = cc While bing = 0 If q <> Last cube q = After q dp# = ((cc\v[0]\m\x - q\v[0]\m\x) * (cc\v[0]\m\x - q\v[0]\m\x)) + ((cc\v[0]\m\y - q\v[0]\m\y) * (cc\v[0]\m\y - q\v[0]\m\y)) + ((cc\v[0]\m\z - q\v[0]\m\z) * (cc\v[0]\m\z - q\v[0]\m\z)) If dp < 6.0 For aa = 0 To 8 For bb = 0 To 8 l# = cc\v[aa]\radius + q\v[bb]\radius dp2# = ((cc\v[aa]\m\x - q\v[bb]\m\x) * (cc\v[aa]\m\x - q\v[bb]\m\x)) + ((cc\v[aa]\m\y - q\v[bb]\m\y) * (cc\v[aa]\m\y - q\v[bb]\m\y)) + ((cc\v[aa]\m\z - q\v[bb]\m\z) * (cc\v[aa]\m\z - q\v[bb]\m\z)) If dp2 < (l * l) SetDistance(cc\v[aa],q\v[bb],l) SubVector(vTemp1,cc\v[aa]\m,cc\v[aa]\old) MulVecScalar2(vTemp1,.4 * fTimeStep) AddVector2(cc\v[aa]\old,vTemp1) EndIf Next Next EndIf Else bing = 1 EndIf Wend Next Next End Function Function SetDistance(v1.VerletPack,v2.VerletPack,dist#) SubVector(vTemp1,v1\m,v2\m) deltalength# = Sqr((vTemp1\x * vTemp1\x) + (vTemp1\y * vTemp1\y) + (vTemp1\z * vTemp1\z)) If deltalength <= 0.0 deltalength = 0.0001 diff# = (deltalength - dist) / deltalength tmass# = v1\mass + v2\mass MulVecScalar(vTemp2,vTemp1,diff * (v2\mass / tmass)) SubVector2(v1\m,vTemp2) MulVecScalar(vTemp2,vTemp1,diff * (v1\mass / tmass)) AddVector2(v2\m,vTemp2) End Function Function CageVerlet2(v.VerletPack) ; Collision code col = False If v\m\x <> EntityX(v\entity) v\m\x=EntityX(v\entity) col = True EndIf If v\m\y <> EntityY(v\entity) v\m\y=EntityY(v\entity) col = True EndIf If v\m\z <> EntityZ(v\entity) v\m\z=EntityZ(v\entity) col = True EndIf If col SubVector(vTemp1,v\m,v\old) MulVecScalar2(vTemp1,0.4 * fTimeStep) AddVector2(v\old,vTemp1) EndIf End Function Function Verlet.VerletPack(x#,y#,z#,radius#, mass# = 1.0, obj%, red,green,blue,surface,mesh,state) v.VerletPack = New VerletPack v\surface=surface v\mesh=mesh v\vertex=AddVertex(v\surface,x,y,z) v\m = Vector(x,y,z) v\entity = CreatePivot() PositionEntity v\entity,x,y,z EntityType v\entity, ACTIVE EntityRadius v\entity,radius# v\old = Vector(x,y,z) v\a = Vector(0.0,0.0,0.0) If radius <= 0.0 radius = 0.01 v\radius = radius If mass <= 0.0 mass = 0.01 v\mass = mass v\obj = obj Return v End Function Function Constraint2.Constraint(v1.VerletPack,v2.VerletPack) c.Constraint = New Constraint c\v1 = v1 c\v2 = v2 c\d = Sqr((v2\m\x - v1\m\x)^2 + (v2\m\y - v1\m\y)^2 + (v2\m\z - v1\m\z)^2) ;Return c ; You may need this someday ... we don't for what we have here End Function ;// Create a Vector Function Vector.Vector(x#=0.0,y#=0.0,z#=0.0) v.Vector = New Vector v\x=x v\y=y v\z=z Return v End Function ;// Vector 1 is set to Vector 2 Function CloneVector(v1.Vector,v2.Vector) v1\x = v2\x v1\y = v2\y v1\z = v2\z End Function ;// Vector Scalar Multiplication ;// Form of Vector1 = Vector2 * Scalar Function MulVecScalar(v1.Vector,v2.Vector,s#) v1\x = v2\x * s v1\y = v2\y * s v1\z = v2\z * s End Function ;// Form of Vector1 = Vector1 + Vector2 Function AddVector2(v1.Vector,v2.Vector) v1\x = v1\x + v2\x v1\y = v1\y + v2\y v1\z = v1\z + v2\z End Function ;// Form of Vector1 = Vector1 - Vector2 Function SubVector2(v1.Vector,v2.Vector) v1\x = v1\x - v2\x v1\y = v1\y - v2\y v1\z = v1\z - v2\z End Function ;// Vector Subtraction ;// Form of Vector1 = Vector2 - Vector3 Function SubVector(v1.Vector,v2.Vector,v3.Vector) v1\x = v2\x - v3\x v1\y = v2\y - v3\y v1\z = v2\z - v3\z End Function ;// Form of Vector1 = Vector1 * Scalar Function MulVecScalar2(v1.Vector,s#) v1\x = v1\x * s v1\y = v1\y * s v1\z = v1\z * s End Function ;************* deltatime function ****************** Global new_time=MilliSecs(), old_time=MilliSecs() Function delta_time#(new_time) delta_t#=(new_time - old_time) * .001 old_time=new_time Return delta_t# End Function ;**************** main loop *************************************** While Not KeyHit(1) fTimeStep#=delta_time(MilliSecs()) TimeStep() For v.VerletPack = Each VerletPack VertexCoords v\surface,v\vertex,v\m\x,v\m\y,v\m\z UpdateNormals v\mesh PositionEntity v\entity,v\m\x,v\m\y,v\m\z Next For temp_cube.cube = Each cube PositionEntity temp_cube\player,EntityX(temp_cube\center\entity),EntityY(temp_cube\center\entity),EntityZ(temp_cube\center\entity) temp_cube\X_vec=EntityX(temp_cube\x1\entity)-EntityX(temp_cube\x2\entity) temp_cube\Y_vec=EntityY(temp_cube\x1\entity)-EntityY(temp_cube\x2\entity) temp_cube\Z_vec=EntityZ(temp_cube\x1\entity)-EntityZ(temp_cube\x2\entity) AlignToVector temp_cube\player, temp_cube\X_vec, temp_cube\Y_vec, temp_cube\Z_vec, 1 temp_cube\X_vec=EntityX(temp_cube\z1\entity)-EntityX(temp_cube\z2\entity) temp_cube\Y_vec=EntityY(temp_cube\z1\entity)-EntityY(temp_cube\z2\entity) temp_cube\Z_vec=EntityZ(temp_cube\z1\entity)-EntityZ(temp_cube\z2\entity) AlignToVector temp_cube\player, temp_cube\X_vec, temp_cube\Y_vec, temp_cube\Z_vec, 3 Next UpdateWorld For v.VerletPack = Each VerletPack CageVerlet2(v) Next PositionEntity cam,0,0,0 RotateEntity cam,MouseY()-height*.5 ,(-MouseX())-width*.5+50,0 MoveEntity cam,0,0,-15 RenderWorld Flip False Wend End