Transformation errors

BlitzMax Forums/MiniB3D Module/Transformation errors

JoshK(Posted 2007) [#1]
Are there any plans to replace the matrix math with quaternions? The transformation and positioning code is very good, but it will only be completely reliable with quaternions. I think fixing the entity system is more important than any additions or emulation of extra Blitz3D routines. In fact, it would be nice to have a bulletproof entity.mod that just handled transformations and rotations.

I notice I only get errors when I try to parent a null-parented entity to another entity. If I take a rotated entity's child and set the parent to null, it works fine.

Here's the quaternion code from my engine. I don't know how to implement this into MiniB3D's matrix system:
Const QuatToEulerAccuracy#=0.001

Global VECTOR_X#
Global VECTOR_Y#
Global VECTOR_Z#
Global VECTOR_W#

Function VectorX#()
	Return VECTOR_X
EndFunction

Function VectorY#()
	Return VECTOR_Y
EndFunction

Function VectorZ#()
	Return VECTOR_Z
EndFunction

Function VectorW#()
	Return VECTOR_W
EndFunction

Function EulerAsQuat(pitch#,yaw#,roll#)
	cr#=Cos(-roll#/2.0)
	cp#=Cos(pitch#/2.0)
	cy#=Cos(yaw#/2.0)
	sr#=Sin(-roll#/2.0)
	sp#=Sin(pitch#/2.0)
	sy#=Sin(yaw#/2.0)
	cpcy#=cp#*cy#
	spsy#=sp#*sy#
	spcy#=sp#*cy#
	cpsy#=cp#*sy#
	VECTOR_w#=cr#*cpcy#+sr#*spsy#
	VECTOR_x#=sr#*cpcy#-cr#*spsy#
	VECTOR_y#=cr#*spcy#+sr#*cpsy#
	VECTOR_z#=cr#*cpsy#-sr#*spcy#
End Function

Function QuatAsEuler(x#,y#,z#,w#)
	sint#=(2.0*w*y)-(2.0*x*z)
	cost_temp#=1.0-(sint#*sint#)
	If Abs(cost_temp#)>QuatToEulerAccuracy
		cost#=Sqr(cost_temp#)
		Else
		cost#=0.0
	EndIf
	If Abs(cost#)>QuatToEulerAccuracy
		sinv#=((2.0*y*z)+(2.0*w*x))/cost#
		cosv#=(1.0-(2.0*x*x)-(2.0*y*y))/cost#
		sinf#=((2.0*x*y)+(2.0*w*z))/cost#
		cosf#=(1.0-(2.0*y*y)-(2.0*z*z))/cost#
		Else
		sinv#=(2.0*w*x)-(2.0*y*z)
		cosv#=1.0-(2.0*x*x)-(2.0*z*z)
		sinf#=0.0
		cosf#=1.0
	EndIf
	VECTOR_z#=-ATan2(sinv#,cosv#)
	VECTOR_x#=ATan2(sint#,cost#)
	VECTOR_y#=ATan2(sinf#,cosf#)
End Function

Function MulQuat(Ax#,Ay#,Az#,Aw#,Bx#,By#,Bz#,Bw#)
	a#=(Aw#+Ax#)*(Bw#+Bx#)
	b#=(Az#-Ay#)*(By#-Bz#)
	c#=(Aw#-Ax#)*(By#+Bz#)
	d#=(Ay#+Az#)*(Bw#-Bx#)
	e#=(Ax#+Az#)*(Bx#+By#)
	f#=(Ax#-Az#)*(Bx#-By#)
	g#=(Aw#+Ay#)*(Bw#-Bz#)
	h#=(Aw#-Ay#)*(Bw#+Bz#)
	VECTOR_w#=b#+(-e#-f#+g#+h#)/2.0
	VECTOR_x#=a#-(e#+f#+g#+h#)/2.0
	VECTOR_y#=c#+(e#-f#+g#-h#)/2.0
	VECTOR_z#=d#+(e#-f#-g#+h#)/2.0
End Function

Function Slerp(Ax#,Ay#,Az#,Aw#,Bx#,By#,Bz#,Bw#,t#)
	If Abs(ax-bx)<0.001 And Abs(ay-by)<0.001 And Abs(az-bz)<0.001 And Abs(aw-bw)<0.001
		VECTOR_x#=ax
		VECTOR_y#=ay
		VECTOR_z#=az
		VECTOR_w#=aw
		Return True
	EndIf
	cosineom#=Ax#*Bx#+Ay#*By#+Az#*Bz#+Aw#*Bw#
	If cosineom# <= 0.0
		cosineom#=-cosineom#
		scaler_w#=-Bw#
		scaler_x#=-Bx#
		scaler_y#=-By#
		scaler_z#=-Bz#
		Else
		scaler_w#=Bw#
		scaler_x#=Bx#
		scaler_y#=By#
		scaler_z#=Bz#
	EndIf
	If (1.0 - cosineom#)>0.00001
		omega#=ACos(cosineom#)
		sineom#=Sin(omega#)
		scale0#=Sin((1.0-t#)*omega#)/sineom#
		scale1#=Sin(t#*omega#)/sineom#
		Else
		scale0#=1.0-t#
		scale1#=t#
		EndIf
	VECTOR_w#=scale0#*Aw#+scale1#*scaler_w#
	VECTOR_x#=scale0#*Ax#+scale1#*scaler_x#
	VECTOR_y#=scale0#*Ay#+scale1#*scaler_y#
	VECTOR_z#=scale0#*Az#+scale1#*scaler_z#
EndFunction

Function TurnQuat(Ax#,Ay#,Az#,Aw#,x#,y#,z#)
	EulerAsQuat(x#,y#,z#)
	mulquat(ax#,ay#,az#,aw#,VECTOR_x#,VECTOR_y#,VECTOR_z#,VECTOR_w#)
EndFunction



North(Posted 2007) [#2]
There was some discussion on this here :

http://blitzbasic.com/Community/posts.php?topic=66809#751294


simonh(Posted 2007) [#3]
MiniB3D uses eulers internally while Blitz3D uses quaternions, so yes, there are some minor differences (most notably TurnEntity, RotateEntity should work the same).

I do have Blitz3D's source code available to make the necessary changes but it's a case of getting round to it.