Me bones are broken

BlitzMax Forums/MiniB3D Module/Me bones are broken

Snixx(Posted 2010) [#1]
I have created a rather nice robot in milkshape and exported to b3d... however I cannot seem to get my bones to work. Using entityyaw etc i can see that they are rotating but the mesh stays static.


Kryzon(Posted 2010) [#2]
Sounds like a skinning problem - the vertices not being properly assigned to bones. Make sure to not leave any vertices without bones.

Does the mesh animate correctly within Milkshape?


Snixx(Posted 2010) [#3]
I have no actual animation, I had planned to animate with code. The mesh is setup perfectly with bones and vertices all attached.

edit: I have just tested my model using the B3D demo version and it works... unlike Minib3d


klepto2(Posted 2010) [#4]
In minib3d you can't animate bones via code. This is one of the few not supported things.


Snixx(Posted 2010) [#5]
Really? thats not too good then, I did actually try your extended version to see if that worked also:P

Minib3d is now a no no sadly:/


Kryzon(Posted 2010) [#6]
If there was enough GLSL hardware skinning information on the web I could try and implement a shader version of the bone system. But apparently that's a very secluded subject.


JetFireDX(Posted 2010) [#7]
I made this a while ago. I don't know if it will serve your needs and can't recall if it works fully. Pretty sure it did and it was my keyframe adding / removing code that didn't yet. I should work on that again sometime...

'Moves a bone the specified distance from where it is now.
'USAGE: moveBone(entity, bone number, key frame number,delta x,delta y, delta z)
Function moveBone(ent:TEntity,bone:Int,frame:Int,dx:Float,dy:Float,dz:Float)
	Local boneCount:Int = 0
	Local frameCount:Int = 0
	For Local currBone:TBone=EachIn ent.entity_list
		frameCount = currBone.keys.frames
		
		If frame > frameCount Then Return
		If frame < 1 Then Return
		
		If boneCount = bone

			'Set bone position.
			Local lastFrame = frame - 1
			Local nextFrame = frame + 1
			
			If lastFrame < 0 Then lastFrame = 0
			If nextFrame > frameCount Then nextFrame = frameCount
			
			'Anim time starts at index 1 in the keyframe arrays
			currBone.keys.px[frame]:+dx
			currBone.keys.py[frame]:+dy
			currBone.keys.pz[frame]:+dz
			currBone.keys.flags[frame]=5
			
		EndIf
		
		boneCount:+1
	Next
End Function

Function rotateBone(ent:TEntity,bone:Int,frame:Int,rx:Float,ry:Float,rz:Float)
	Local boneCount:Int = 0
	Local frameCount:Int = 0
	For Local currBone:TBone=EachIn ent.entity_list
		frameCount = currBone.keys.frames
		
		If frame > frameCount Then Return
		If frame < 1 Then Return
		
		If boneCount = bone

			'Set bone rotation.
			Local lastFrame = frame - 1
			Local nextFrame = frame + 1
			
			If lastFrame < 0 Then lastFrame = 0
			If nextFrame > frameCount Then nextFrame = frameCount
			
			
			Local w:Float,x:Float,y:Float,z:Float
			
			EulerToQuart(ry,rx,rz,w,x,y,z)
			
			currBone.keys.qw[frame] = w
			currBone.keys.qx[frame] = x
			currBone.keys.qy[frame] = y
			currBone.keys.qz[frame] = z
			currBone.keys.flags[frame] = 5
			
			'Set the bones position to the initial position... otherwise if this
			'bone has not been rotated before, it will move to 0,0,0
			
			currBone.keys.px[frame] = currBone.n_px#
			currBone.keys.py[frame] = currBone.n_py#
			currBone.keys.pz[frame] = currBone.n_pz#
			
		EndIf
		
		boneCount:+1
	Next
End Function

Function EulerToQuart(yaw:Float,pitch:Float,roll:Float,w:Float Var,x:Float Var,y:Float Var,z:Float Var)
	'Ported on 08/17/2008 from
	'http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm

	Local c1:Float = Cos(yaw/2),c2:Float=Cos(pitch/2),c3:Float = Cos(roll/2)
	Local s1:Float = Sin(yaw/2),s2:Float=Sin(pitch/2),s3:Float = Sin(roll/2)
	
	Local c1c2:Float = c1*c2 
	Local s1s2:Float = s1*s2
	
	w = (c1c2 * c3) - (s1s2 * s3)
	x = (c1c2 * s3) + (s1s2 * c3)
	y = (s1 * c2 * c3) + (c1* s2 * s3)
	z = (c1 * s2 * c3) - (s1 * c2 * s3)
EndFunction



Kryzon(Posted 2010) [#8]
Thanks for sharing that code, JetFireDX.

If those Cos and Sin calls where replaced with pre-computed tables for each, would that actually improve the performance of this EulerToQuart() function?


JetFireDX(Posted 2010) [#9]
No problem. I hope it works for you. Sorry for the late response, I've been moving house and don't have internet access yet.

I doubt that pre-computing the sin/cos values would give much if any benefit. The last bit of code from BlitzBasic 2 on the Amiga I brought over to the PC years and years ago was actually faster to directly call sin/cos rather than use a lookup table. Wouldn't hurt to try it though. You could also do the yaw/2, pitch/2, and roll/2 just once rather than in each sin/cos call.


Kryzon(Posted 2010) [#10]
No worries man, good luck with your moving.

It seems lookup tables are faster:

...and precalculating the divisions over two like you said should spare some nanoseconds as well.