Help with maths problem please..

Blitz3D Forums/Blitz3D Programming/Help with maths problem please..

Rad Gravity(Posted 2005) [#1]
This thing is really bugging me now, I have tried several methods to implement basic ball physics but to no avail. The damn thing just will not bounce. I know elasticity can never be > 100% (not in the real world at least), and that changing velocities along the collision normal is the standard way of implementing ball physics so why doesn't this code work? Any help would be appreciated.

Here is the code:

For c = 1 To CountCollisionsBlitz(ball\entity)
If CollisionHitTypeBlitz(ball\entity,c) = TYPE_WORLD Then

; get vector using collision normals
nx#=CollisionHitNormBlitz(ball\entity,c,1)
ny#=CollisionHitNormBlitz(ball\entity,c,2)
nz#=CollisionHitNormBlitz(ball\entity,c,3)

; get dot product of ball vector and normal vector
vDot#=((nx#*ball\velocity#[0]) + (ny#*ball\velocity#[1]) + (nz#*ball\velocity#[2]))

; factor in elasticity
vDot#=vDot#*(1+ball\elasticity#)

; set new velocity
ball\velocity#[0]=ball\velocity#[0]-(vDot#*nx#)
ball\velocity#[1]=ball\velocity#[1]-(vDot#*ny#)
ball\velocity#[2]=ball\velocity#[2]-(vDot#*nz#)
EndIf
Next


sswift(Posted 2005) [#2]
I'm a bit rusty at this because I haven't coded physics in a few months, but looking at my own code which handles balls bouncing off levels, it looks like you failed to do several things like multiply the result by -2.0, and you're missing some abs things I have in another spot.

Here's my code. Make of it what you will. :-)

; -------------------------------------------------------------------------------------------------------------------
; This subroutine animates the sphere.
; -------------------------------------------------------------------------------------------------------------------
.Animate_Sphere


	; Check to see if the entity collided with the level last frame.
	Entity_Hit = EntityCollided(ballpos, COLLIDE_Level)

	; If the entity collided with the level, then store the time of the last collision.	
	If Entity_Hit Then Last_Collide_Time = Time_Now 
					
	; Calculate motion friction:

		; Calculate the entity's current velocity.
		Velocity# = Sqr(Vx#^2 + Vy#^2 + Vz#^2)

		; If the entity is not traveling fast enough to be motion blurred:
		If Velocity# < 6.0
			
			; If motion blur is on, turn it off:
			If Motion_Blur = True

				SPS_DELETE_CHILD_EMITTERS(ballpos)
				Motion_Blur = False

			EndIf

		EndIf
		
		; If the entity is moving, adjust it's velocity:
		If Velocity# > 0 

			; Calculate the direction vector.
			; The direction vector has a length of 1.
			Direction_X# = Vx# / Velocity#
			Direction_Y# = Vy# / Velocity#
			Direction_Z# = Vz# / Velocity#

			; Compute air friction.
			; Air friction is dependent on the speed of the entity, and will prevent it from accelerting forever.
			Air_Friction_Force# = AIR_FRICTION_CONSTANT# * Velocity#^2.0	
			Velocity# = Velocity# - (Air_Friction_Force# * Time_Delta_Sec#)
	
			; If the entity is colliding with the level this frame, or still sticking to the level from it's last
			; collision, then apply ground friction.
			If (Time_Now - Last_Collide_Time) <= Player_Friction_Stick_Time 

				; Compute ground friction.  Ground friction is not dependent on the speed of the entity.
				Velocity# = Velocity# - (GROUND_FRICTION_CONSTANT# * Time_Delta_Sec#)

			EndIf


			; Make sure the entity's velocity doesn't go below 0.
			; It is impossible to have a negative velocity in physics and "bad things" happen if you try to.
			If (Velocity# < 0) Then Velocity# = 0			


			; Convert the entity's velocity and direction back into a motion vector.
			Vx# = Direction_X# * Velocity#
			Vy# = Direction_Y# * Velocity#
			Vz# = Direction_Z# * Velocity#


			; If the entity collided with the level, make it bounce.
			If Entity_Hit > 0 

				; Calculate bounce:

	    			; Get the normal of the surface which the entity collided with.    
					Nx# = CollisionNX(ballpos, 1)
					Ny# = CollisionNY(ballpos, 1)
					Nz# = CollisionNZ(ballpos, 1)
		
				; Multiply the entity's motion vector by the surface normal.
				; This gives us the part of the vector which points in the same direction as the surface the object collided with.

					Elasticity# = 0.5 

					Vx# = Vx# - Vx#*Abs(Nx#)*(1.0 - Elasticity#)
					Vy# = Vy# - Vy#*Abs(Ny#)*(1.0 - Elasticity#)
					Vz# = Vz# - Vz#*Abs(Nz#)*(1.0 - Elasticity#)
			
				; Compute the dot product of the entity's motion vector and the normal of the surface collided with.
					VdotN# = Vx#*Nx# + Vy#*Ny# + Vz#*Nz#
							
				; Calculate the normal force.
					NFx# = -2.0 * Nx# * VdotN#
					NFy# = -2.0 * Ny# * VdotN#
					NFz# = -2.0 * Nz# * VdotN#

				; Add the normal force to the direction vector.
					Vx# = Vx# + NFx#
					Vy# = Vy# + NFy#
					Vz# = Vz# + NFz#
	
				; Do not allow the entity to move vertically.
				;	If Vy# > 0 Then Vy# = 0
	
			EndIf


		EndIf

	
	; Apply directional thrust:

		; If the entity collided with the level, apply directional thrust.
		;If Entity_Hit > 0 
		
			; Take thrust in object space, and translates it to an XYZ vector in world space.
			;TFormVector 0, 0, Thrust#, ballpos, 0

			; Add any thrust being applied this frame.
			; There's a very good reason why this is done AFTER the friction is calculated.
			; It involves inequalities in force cause by variable framerates.
			Vx# = Vx# + (Thrust_X# * Time_Delta_Sec#)
			Vz# = Vz# + (Thrust_Z# * Time_Delta_Sec#)

		;EndIf


	; Apply gravity:
		Vy# = Vy# - (GRAVITY# * Time_Delta_Sec#)


	; Move and rotate the entity:

		; We rotate the entity by the actual distance moved and not by the velocity because if we rotate according
		; to the velocity then the entity will roll when it's up against a wall and not moving.

		OldX# = NewX#
		OldZ# = NewZ#

		TranslateEntity ballpos, Vx#*Time_Delta_Sec#, Vy#*Time_Delta_Sec#, Vz#*Time_Delta_Sec#, True

		NewX# = EntityX#(ballpos, True)
		NewZ# = EntityZ#(ballpos, True)
		
		Mx# = (NewX# - OldX#)
		Mz# = (NewZ# - OldZ#)		

		; Rotate the entity the right amount for it's radius and the distance it has moved along the X and Z axis.
		; This is kinda a hack and only designed for rolling on planes but you won't notice the diffrence.
		XAngleAdjust# = (Mx# / BallRadius#) * (180.0/Pi) 
		ZAngleAdjust# = (Mz# / BallRadius#) * (180.0/Pi)
	    TurnEntity ball,ZAngleAdjust#,0,-XAngleAdjust#,True


Return



Rad Gravity(Posted 2005) [#3]
Sorry dude, all the normal force calculations were in one of the earlier attempts I made and didn't work. I decided to strip out a lot of code that I was writing in desperation and get back to basics. I just tried your code in case I had made a mistake but to no avail. The ball still does not bounce. Thanks for your help though, I think it may be something else in my code like the collision detection or something as I think the math is basically sound.


Rad Gravity(Posted 2005) [#4]
Just in case you're interested, it was the collision routine that was the problem, the count of collisions exceeded 1 on initial impact and the normals for subsequent collisions were screwed up.


Rook Zimbabwe(Posted 2005) [#5]
I saw this same thing a few months ago... Search the code archives I think it was Matty who initiated the topic (not sure) but a good search would be BOUNCE