Secrets of Chain Physics Revealed!

Blitz3D Forums/Blitz3D Programming/Secrets of Chain Physics Revealed!

JoshK(Posted 2003) [#1]
I don't have time to pursue this. Maybe someone else can add the rigid bodies. I had some success with making objects out of cross-linked chains, but it got to be too many chains for even a simple cube.

The missing code is the part that adjusts the rotation of the object. I suggest building off of what i have, rather than doing a whole new routine.

Do not ask me for support.

Demo program:
Include "physics.bb"

Graphics3D 800,600,16,2
SetBuffer BackBuffer()

Global cam=CreateCamera()
MoveEntity cam,0,30,-45
TurnEntity cam,35,0,0
;MoveEntity cam,0,0,-24

g=LoadMesh("start.b3d")
ScaleMesh g,.10,.10,.10
MoveEntity g,0,-15,30
;RotateEntity g,0,0,5

;g=CreatePlane()
EntityType g,2
;MoveEntity g,0,-10,0
;EntityColor g,100,100,100
;
For n=1 To 0
	g=CreateCube()
	RotateEntity g,0,90+45,0
	MoveEntity g,2*n+50,-10+n*2,-50
	ScaleEntity g,1,1,100
	EntityType g,2
	EntityColor g,100,100,100
	Next

;g=CreateCube()
;ScaleMesh g,20,20,20
;MoveEntity g,0,0,20
;FlipMesh g

r#=1.5
m=CreateSphere()
EntityShininess m,1
EntityType m,1
EntityRadius m,r
ScaleMesh m,r,r,r
HideEntity m

l=CreateLight()
RotateEntity l,25,45,0
EntityParent l,cam

Collisions 1,2,2,2
Collisions 1,1,1,2

link=CreateSphere()
EntityType link,1
EntityRadius link,1
HideEntity link

For m=1 To 6
For n=1 To 6
	link=CopyEntity(link)
	EntityColor link,Rand(255),Rand(255),Rand(255)
	If n=1
		firstlink=link
		;entitymass link,100000
		PositionEntity link,Rnd(-32,33),20,Rnd(-32,32)
		EndIf
	If n=1 And m<>6
		ScaleEntity link,2,2,2
		EntityRadius link,2
		enablephysics link,0
		entitymass link,100000
		Else
		PositionEntity link,EntityX(firstlink),20-5*n,EntityZ(firstlink)
		ScaleEntity link,r,r,r
		EntityRadius link,r
		enablephysics link,11
		;entityelasticity link,0.9
		entityfriction link,0.01
		EndIf
	If n=2
		chain=createchain(link,lastlink,5)
		EndIf
	If n>2
		chain=createchain(link,lastlink,5)
		EndIf
	lastlink=link
	Next
	;If ll<>0 And m<>6 createchain ll,firstlink,5
ll=link
Next

entitymass link,20

rb.rigidbody=New rigidbody
ball=CopyMesh(link)
ScaleEntity ball,1,1,1
EntityType ball,0
rb\mesh=ball

Include "CreateRigidCube.bb"

ball=CopyMesh(link)
ScaleEntity ball,2,2,2
EntityType ball,1
EntityRadius ball,2
MoveEntity ball,5,0,0
EntityColor ball,255,0,0
ph.physics=enablephysics(ball,11)
ph\body=rb
entityelasticity ball,0.9
entityfriction ball,0.01

ball=CopyMesh(link)
ScaleEntity ball,2,2,2
EntityType ball,1
EntityRadius ball,2
MoveEntity ball,-5,0,0
EntityColor ball,255,0,0
ph.physics=enablephysics(ball,11)
ph\body=rb
entityelasticity ball,0.9
entityfriction ball,0.01

period=1000/60
time=MilliSecs()-period

While Not KeyHit(1)
	
	Repeat
		elapsed=MilliSecs()-time
		Until elapsed
	
	ticks=elapsed/period
	tween#=Float(elapsed Mod period)/Float(period)
	
	For k=1 To ticks
		time=time+period
			
		If KeyDown(28)
			;r=Rand(2)+1
			r=3
			ball=CopyMesh(link)
			ScaleEntity ball,r,r,r
			EntityRadius ball,r
			EntityType ball,1
			PositionEntity ball,Rnd(-20,20),Rnd(20),Rnd(-20,20)
			enablephysics ball,11
			entitymass ball,2;r^2
			EntityElasticity ball,0.98
			EntityColor ball,Rand(255),Rand(255),Rand(255)
			EntityFriction ball,0.01
			MoveEntity ball,Rnd(-2,2),Rnd(-2,2),Rnd(-2,2)
			balls=balls+1
			If lastball
				;If Rand(2)=1 createchain lastball,ball,10
				lastball=0
				Else
				lastball=ball
				EndIf
			EndIf

		TranslateEntity link,0.05*(KeyDown(205)-KeyDown(203)),0.5*KeyDown(16),0.05*(KeyDown(200)-KeyDown(208))

		UpdatePhysics 1
	
		Next
		
	RenderWorld
	
	Text 0,0,fps()
	Text 0,20,"Press Q to lift chain."
	Text 0,40,"Arrow keys move chain"
	Text 0,60,"Press enter to add balls."
	Text 0,80,balls+" balls."
	
	Flip
	
	Wend

Global FPS_fpstime
Function FPS()
oldtime=FPS_fpstime
FPS_fpstime=MilliSecs()
elapsed=FPS_fpstime-oldtime
If Not elapsed elapsed=1
FPS_fps=1000/elapsed
Return FPS_FPS
End Function


Physics routines ("physics.bb"):
Type bond
Field mesh
Field a.physics, b.physics
Field length#
Field nextlink.bond
Field updated
Field offsetA#
Field offsetb#
End Type

Type rigidbody
Field mesh
Field points
End Type

Type physics
Field mesh
Field velocity#[5]
Field elasticity#
Field mass#
Field flags
Field friction#[1]
Field position#[5]
Field compression#[1]
Field dvelocity#[5]
Field offset#[2]
Field body.rigidbody
End Type

Function CreateChain(a,b,length#)
ph.physics=findphysics(a)
If ph=Null RuntimeError "Entity does not have physics enabled."
ph2.physics=findphysics(b)
If ph2=Null RuntimeError "Entity does not have physics enabled."
l.bond=New bond
l\mesh=CreateCube()
l\a=ph
l\b=ph2
l\length=length
loffseta=Rnd(-90,90)
loffsetb=Rnd(-90,90)
Return Handle(l)
End Function

Function AddLink(chain,link,length#)
ph.physics=findphysics(link)
If ph=Null RuntimeError "Entity does not have physics enabled."
l2.bond=Object.bond(chain)
l.bond=New bond
l2\nextlink=l
l\mesh=CreateCube()
l\a=l2\b
l\b=ph
l\length=length/2
Return Handle(l)
End Function

Function UpdatePhysics(detail=2)

For ph.physics=Each physics

	;update velocity
	If 2^0 And ph\flags
		If 2^3 And ph\flags
			ph\velocity[0]=ph\velocity[0]+EntityX(ph\mesh,1)-ph\position[0]
			ph\velocity[1]=ph\velocity[1]+EntityY(ph\mesh,1)-ph\position[1]
			ph\velocity[2]=ph\velocity[2]+EntityZ(ph\mesh,1)-ph\position[2]		
			EndIf
		EndIf

	ph\position[0]=EntityX(ph\mesh,1)
	ph\position[1]=EntityY(ph\mesh,1)
	ph\position[2]=EntityZ(ph\mesh,1)

	;gravity	
	If 2^1 And ph\flags
		ph\velocity[1]=ph\velocity[1]-0.05
		EndIf
	;execute translational velocity
	If 2^0 And ph\flags
		TranslateEntity ph\mesh,ph\velocity[0],ph\velocity[1],ph\velocity[2],1
		;TranslateEntity ph\mesh,Rnd(-0.00001,0.00001),Rnd(-0.0001,0.0001),Rnd(-0.0001,0.0001),1
		EndIf
		
	;execute rotational velocity
	If 2^2 And ph\flags TurnEntity ph\mesh,ph\velocity[3],ph\velocity[4],ph\velocity[5],1	

	ph\position[3]=EntityX(ph\mesh,1)
	ph\position[4]=EntityY(ph\mesh,1)
	ph\position[5]=EntityZ(ph\mesh,1)
	
	Next

UpdateWorld

For ph.physics=Each physics
	ph\velocity[3]=ph\velocity[0]
	ph\velocity[4]=ph\velocity[1]
	ph\velocity[5]=ph\velocity[2]
	ph\velocity[0]=EntityX(ph\mesh,1)-ph\position[0]
	ph\velocity[1]=EntityY(ph\mesh,1)-ph\position[1]
	ph\velocity[2]=EntityZ(ph\mesh,1)-ph\position[2]
	Next

;transfer inertia
For ph.physics=Each physics
	vx#=ph\velocity[3]-ph\velocity[0]
	vy#=ph\velocity[4]-ph\velocity[1]
	vz#=ph\velocity[5]-ph\velocity[2]
	For c=1 To CountCollisions(ph\mesh)
		collider=CollisionEntity(ph\mesh,c)
		x#=CollisionX(ph\mesh,c)
		y#=CollisionY(ph\mesh,c)
		z#=CollisionZ(ph\mesh,c)
		nx#=Abs(CollisionNX(ph\mesh,c))
		ny#=Abs(CollisionNY(ph\mesh,c))
		nz#=Abs(CollisionNZ(ph\mesh,c))
		
		Select GetEntityType(collider)
;			;Spheres
			Case 1	
			k#=0.5		
				ph2.physics=findphysics(collider)
				If ph2<>Null
					ph2\velocity[0]=ph2\velocity[0]+vx*k*ph\mass/ph2\mass
					ph2\velocity[1]=ph2\velocity[1]+vy*k*ph\mass/ph2\mass
					ph2\velocity[2]=ph2\velocity[2]+vz*k*ph\mass/ph2\mass
					Exit
					EndIf	
			;Polygons with infinite mass
			Case 2
			k#=0.8
				If k*nx*Abs(ph\velocity[3])>Abs(ph\velocity[0]) ph\velocity[0]=ph\velocity[0]*(1.-k*nx)-ph\velocity[3]*nx*k
				If k*ny*Abs(ph\velocity[4])>Abs(ph\velocity[1]) ph\velocity[1]=ph\velocity[1]*(1.-k*ny)-ph\velocity[4]*ny*k
				If k*nz*Abs(ph\velocity[5])>Abs(ph\velocity[2]) ph\velocity[2]=ph\velocity[2]*(1.-k*nz)-ph\velocity[5]*nz*k
			End Select
		Next
	Next

;add friction
For ph.physics=Each physics
	If EntityCollided(ph\mesh,2)
		For n=0 To 5
			;sliding friction
			ph\velocity[n]=ph\velocity[n]*ph\friction[0]
			;static friction
			If Abs(ph\velocity[n])<ph\friction[1] ph\velocity[n]=0.0
			Next
		EndIf
	Next

;save positions for automatic velocity updating
For ph.physics=Each physics
	ph\position[0]=EntityX(ph\mesh,1)
	ph\position[1]=EntityY(ph\mesh,1)
	ph\position[2]=EntityZ(ph\mesh,1)	
	Next

;handle chains
For b.bond=Each bond
	ScaleEntity b\mesh,1,1,1
	fma#=b\a\mass/(b\a\mass+b\b\mass)
	fmb#=b\b\mass/(b\a\mass+b\b\mass)	
	PositionEntity b\mesh,EntityX(b\a\mesh,1)*fma+EntityX(b\b\mesh,1)*fmb,EntityY(b\a\mesh,1)*fma+EntityY(b\b\mesh,1)*fmb,EntityZ(b\a\mesh,1)*fma+EntityZ(b\b\mesh,1)*fmb
	AlignToVector b\mesh,EntityX(b\a\mesh,1)-EntityX(b\b\mesh,1),EntityY(b\a\mesh,1)-EntityY(b\b\mesh,1),EntityZ(b\a\mesh,1)-EntityZ(b\b\mesh,1),3
	MoveEntity b\mesh,0,0,(0.5-fma)*b\length
	TFormPoint 0,0,b\length/2.0,b\mesh,0
	PositionEntity b\a\mesh,TFormedX(),TFormedY(),TFormedZ(),1
	TFormPoint 0,0,-b\length/2.0,b\mesh,0
	PositionEntity b\b\mesh,TFormedX(),TFormedY(),TFormedZ(),1
	ScaleEntity b\mesh,.25,.25,0.5*pointdistance(EntityX(b\b\mesh,1),EntityY(b\b\mesh,1),EntityZ(b\b\mesh,1),EntityX(b\a\mesh,1),EntityY(b\a\mesh,1),EntityZ(b\a\mesh,1))	
	Next

For rb.rigidbody=Each rigidbody
	x#=0.0
	y#=0.0
	z#=0.0
	yaw#=0.0
	n=0
	For ph.physics=Each physics
		If ph\body=rb
			x=x+EntityX(ph\mesh,1)
			y=y+EntityY(ph\mesh,1)
			z=z+EntityZ(ph\mesh,1)
			TFormPoint ph\offset[0],ph\offset[1],ph\offset[2],rb\mesh,0
			dx#=EntityX(ph\mesh,1)-EntityX(rb\mesh,1)
			dy#=EntityY(ph\mesh,1)-EntityY(rb\mesh,1)
			dz#=EntityZ(ph\mesh,1)-EntityZ(rb\mesh,1)
			Normalize dx,dy,dz
			If n=0 AlignToVector rb\mesh,dx,0,dz,1 Else AlignToVector rb\mesh,-dx,0,-dz,1
			If EntityYaw(rb\mesh,1)<0.0 yu=360.0+EntityYaw(rb\mesh,1) Else yu=EntityYaw(rb\mesh,1)
			yaw=yaw+yu
			n=n+1
			EndIf
		Next
	x=x/Float(n)
	y=y/Float(n)
	z=z/Float(n)
	yaw=yaw/Float(n)
	PositionEntity rb\mesh,x,y,z,1
	RotateEntity rb\mesh,0,yaw,0,1
	For ph.physics=Each physics
		If ph\body=rb
			TFormPoint ph\offset[0],ph\offset[1],ph\offset[2],rb\mesh,0
			PositionEntity ph\mesh,TFormedX(),TFormedY(),TFormedZ()
			EndIf
		Next
	Next

End Function

Function MoveLinks(entity,x#,y#,z#)
If KeyDown(57)
For b.bond=Each bond
	If b\updated=False
		If b\a\mesh=entity
			TranslateEntity b\b\mesh,x,y,z,1
			b\updated=True
			movelinks b\b\mesh,x,y,z
		ElseIf b\b\mesh=entity
			TranslateEntity b\a\mesh,x,y,z,1
			b\updated=True
			movelinks b\a\mesh,x,y,z
			EndIf
		EndIf
	Next
	EndIf
End Function

Function CreateVerletCube()

End Function

Function EntityCompression(ease#,max#)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
ph\Compression[0]=ease
ph\Compression[1]=max
End Function

Function PointDistance#( x1#,y1#,z1#,x2#,y2#,z2# )
Return Sqr#((x1-x2)^2+(y1-y2)^2+(z1-z2)^2)
End Function

Function EntityFriction(e,sliding#,static#=0.0001)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
ph\friction[0]=1.0-sliding
ph\friction[1]=static
End Function

Function FindPhysics.physics(e)
For ph.physics=Each physics
	If ph\mesh=e Return ph
	Next
Return Null
End Function

Function EnablePhysics.physics(e,flags=9)
ph.physics=findphysics(e)
If ph=Null ph=New physics
For n=0 To 5
	ph\velocity[n]=0
	Next
ph\mesh=e
ph\mass=1.0
ph\elasticity=0.0
ph\flags=flags
ph\friction[0]=0.9
ph\friction[1]=0.001
ResetEntity e
ph\position[0]=EntityX(e,1)
ph\position[1]=EntityY(e,1)
ph\position[2]=EntityZ(e,1)
ph\compression[0]=0.8
ph\compression[1]=1.5
ph\offset[0]=EntityX(e)
ph\offset[1]=EntityY(e)
ph\offset[2]=EntityZ(e)
Return ph
End Function

Function DisablePhysics(e)
ph.physics=findphysics(e)
If ph<>Null Delete ph
End Function

Function EntityElasticity(e,m#)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
ph\Elasticity=m
End Function

Function AccelerateEntity(e,x#,y#,z#)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
ph\velocity[0]=ph\velocity[0]+x
ph\velocity[1]=ph\velocity[1]+y
ph\velocity[2]=ph\velocity[2]+z
End Function

Function EntityVelocity(e,x#,y#,z#)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
ph\velocity[0]=x
ph\velocity[1]=y
ph\velocity[2]=z
End Function

Function EntityInertia(e,x#,y#,z#)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
ph\velocity[0]=x/ph\mass
ph\velocity[1]=y/ph\mass
ph\velocity[2]=z/ph\mass
End Function

Function EntityMass(e,m#)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
ph\mass=m
End Function

Function GetEntityMass#(e,m#)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
Return ph\mass
End Function

Function EntityInertiaX#(e)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
Return ph\mass*ph\velocity[0]
End Function

Function EntityInertiaY#(e)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
Return ph\mass*ph\velocity[1]
End Function

Function EntityInertiaZ#(e)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
Return ph\mass*ph\velocity[2]
End Function

Function EntityVelocityX#(e)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
Return ph\velocity[0]
End Function

Function EntityVelocityY#(e)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
Return ph\velocity[1]
End Function

Function EntityVelocityZ#(e)
ph.physics=findphysics(e)
If ph=Null RuntimeError "Entity does not have physics enabled."
Return ph\velocity[2]
End Function



poopla(Posted 2003) [#2]
Ill analyze this when I continue work on the Verlet code miracle had been getting at. Don't have time atm. Thanks Halo.


Jeremy Alessi(Posted 2003) [#3]
Pretty cool stuff. I'll be checking into this. I used some pretty good physics in Aerial Antics for gameplay purposes but this can go even further. Getting the rotations right is a hassle but I have a book on it.