TurnEntity - Quaternion Example

BlitzMax Modules Forums/MiniB3D/TurnEntity - Quaternion Example

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

turn your total x,y,z eular rotations into a quat and apply like this, is this what you were meaning?

my old quat routines aint a best fit for minib3d but they could easily be modified to work with a 2d ([,]) array instead of a flat 1d ([]) array

at any rate I dont want to spoil the fun, (gotta leave you somthing to do! ;) )

Import sidesign.minib3d

SuperStrict

Local width:Int=640,height:Int=480,depth:Int=16,mode:Int=0

Graphics3D width,height,depth,mode

Local cam:TCamera=CreateCamera()
PositionEntity cam , 0 , 0 , - 10

Local light:TLight=CreateLight(1)
Local cube:TMesh = CreateCube()
ScaleMesh cube , 1 , 1 , 3
PositionEntity cube , 10 , 0 ,0

Global zerospot:tentity=CreateCube()
ScaleEntity zerospot , 0.1 , 0.1 , 0.1

' used by camera code
Local mxs#=0
Local mys#=0
Local move#=0.5

' used by fps code
Local old_ms#=MilliSecs()
Local renders:Int
Local fps:Int

MoveMouse width / 2 , height / 2


RotateEntity cube , 45,45,45


Global m:Float[16]
Global cubeQuat:Tquat=New Tquat
Local m2:Float Ptr=cube.mat.grid
m[0]=m2[0]
m[4]=m2[4]
m[8]=m2[8]
m[1]=m2[1]
m[5]=m2[5]
m[9]=m2[9]
m[2]=m2[2]
m[6]=m2[6]
m[10] = m2[10]
cubequat.frommatrix(m)
	

Global xturn:Tquat=New TQuat
'xturn.w=0.99996192306417131   ' a x rotation
'xturn.x = 0.0087265354983739347

xturn.w=0.99996192306417131	' a z roatation
xturn.z=0.0087265354983739347

While Not KeyDown(KEY_ESCAPE)		

	If KeyHit(KEY_ENTER) Then DebugStop

	'' control camera
	
	' mouse look
	
	
	mxs#=mxs#+((MouseX()-width/2)/5.0)
	mys#=mys#+((MouseY()-height/2)/5.0)

	RotateEntity cam,mys#,-mxs#,0

	MoveMouse width/2,height/2

	' move camera forwards/backwards/left/right with cursor keys
	
	If KeyDown(KEY_UP)=True Then MoveEntity cam,0,0,move# ' move camera forward
	If KeyDown(KEY_DOWN)=True Then MoveEntity cam,0,0,-move# ' move camera back

	If KeyDown(KEY_LEFT)=True Then MoveEntity cam,-move#,0,0 ' move camera left
	If KeyDown(KEY_RIGHT)=True Then MoveEntity cam,move#,0,0 ' move camera right
	
	''
	
'	TurnEntity cube,1,0,0

	cubequat.multiply(xturn)

		 
	m = cubequat.tomatrix()
	Local m2:Float Ptr=cube.mat.grid
	m2[0]=m[0]
	m2[4]=m[4]
	m2[8]=m[8]
	m2[1]=m[1]
	m2[5]=m[5]
	m2[9]=m[9]
	m2[2]=m[2]
	m2[6]=m[6]
	m2[10] = m[10]
	
	RenderWorld
	renders=renders+1

	' calculate fps
	If MilliSecs()-old_ms>=1000
		old_ms=MilliSecs()
		fps=renders
		renders=0
	EndIf
	
	Text 0,0,"FPS: "+String(fps)
	displaymat(m , 20 , 20)
	
	text 20 , 100 , "q " + cubequat.x + "  " + cubequat.y + "  " + cubequat.z + "  " + cubequat.w
	text 20 , 120 , "t " + xturn.x + "  " + xturn.y + "  " + xturn.z + "  " + xturn.w
	
	Flip

Wend
End

Function floatString:String(v#,d:Int=4,p:Int=4)
	Local m$, e$, r$,  n:Int,  x#=Abs(v)
	If p>0 Then m$=Int((x-Floor(x))*10^p) ; e$="."+Right$("000000"+m$,p)
	If p=0 Or Len(m$)>p Then n=Int(x) Else n=Floor(x)
	If v<0 Then r$="-"+n Else r$=n 
	Return RSet$(r$,d)+e$
End Function

Function displaymat(m:Float[],x:Int,y:Int)
'	glpushmatrix
	For Local i:Int=0 To 3
		For Local j:Int=0 To 3
			GLDrawText FloatString(m[i*4+j]),j*80+x,i*12+y
		Next
	Next
'	glpopmatrix
EndFunction

Type TVec3
	Field x#,y#,z#
	
	Method Set(nx#,ny#,nz#)
		x=nx;y=ny;z=nz
	EndMethod
	
	Method Normalise()
		Local l:Float
		l=Sqr(x*x+y*y+z*z)
		If l=1 Then Return 
		x:/l
		y:/l
		z:/l	
	EndMethod
EndType

Type TQuat
	Field x#,y#,z#,w#
	Method FromMatrix(mat:Float[])
		Local T:Float= 1 + mat[0] + mat[5] + mat[10]
		Local S:Float
		If ( T > 0.00000001 ) Then
			S = Sqr(T) * 2
			X = ( mat[6] - mat[9] ) / S
			Y = ( mat[8] - mat[2] ) / S
			Z = ( mat[1] - mat[4] ) / S
			W = 0.25 * S
			Return
		EndIf
		
		If mat[0] > mat[5] And mat[0] > mat[10] Then	'Column 0: 
        			S  = Sqr( 1.0 + mat[0] - mat[5] - mat[10] ) * 2
        			X = 0.25 * S
		        	Y = (mat[1] + mat[4] ) / S
   		     	Z = (mat[8] + mat[2] ) / S
		        	W = (mat[6] - mat[9] ) / S
		ElseIf mat[5] > mat[10]							'Column 1: 
			S  = Sqr( 1.0 + mat[5] - mat[0] - mat[10] ) * 2
			X = (mat[1] + mat[4] ) / S
			Y = 0.25 * S
			Z = (mat[6] + mat[9] ) / S
			W = (mat[8] - mat[2] ) / S
		Else											'Column 2:
			S  = Sqr( 1.0 + mat[10] - mat[0] - mat[5] ) * 2
			X = (mat[8] + mat[2] ) / S
			Y = (mat[6] + mat[9] ) / S
			Z = 0.25 * S
			W = (mat[1] - mat[4] ) / S
    	EndIf

	EndMethod
	
	Method ToMatrix:Float[]()
		Local xx!=x*x
		Local xy!=x*y
		Local xz!=x*z
		Local xw!=x*w
		
		Local yy!=y*y
		Local yz!=y*z
		Local yw!=y*w
		
		Local zz!=z*z
		Local zw!=z*w
		
		Local m:Float[16]
		m[0]= 1-2*(yy+zz)
		m[4]=   2*(xy-zw)
		m[8]=   2*(xz+yw)
		
		m[1]=   2*(xy+zw)
		m[5]= 1-2*(xx+zz)
		m[9]=   2*(yz-xw)
		
		m[2]=   2*(xz-yw)
		m[6]=   2*(yz+xw)
		m[10]=1-2*(xx+yy)
		
		m[12]=0;m[13]=0;m[14]=0
		m[3]=0;m[7]=0;m[11]=0
		m[15]=1
		
		Return m
		
	EndMethod
	
	Method Normalise()
		Local m:Float
		m=Sqr(w*w+x*x+y*y+z*z)
		If m=1 Then Return ' is exactly 1 more often than you'd think...
		w:/m
		x:/m
		y:/m
		z:/m
	EndMethod
	
	Method FromAxisAngle(a#,axis:TVec3)
		Local sin_a# = Sin( a / 2 )
	    	Local cos_a# = Cos( a / 2 )

	    	X    = axis.x * sin_a
	    	Y    = axis.y * sin_a
	    	Z    = axis.z * sin_a
	    	W    = cos_a

		Normalise()
		Return
	EndMethod

	
	Method Multiply:TQuat(q:TQuat)
		Local a#, b#, c#, d#, e#, f#, g#, h#

		a = (w + x) * (q.w + q.x)
		b = (z - y) * (q.y - q.z)
		c = (w - x) * (q.y + q.z)
		d = (y + z) * (q.w - q.x)
		e = (x + z) * (q.x + q.y)
		f = (x - z) * (q.x - q.y)
		g = (w + y) * (q.w - q.z)
		h = (w - y) * (q.w + q.z)
		
		w = b + (-e - f + g + h) / 2
		x = a - ( e + f + g + h) / 2
		y = c + ( e - f + g - h) / 2
		z = d + ( e - f - g + h) / 2
		
	End Method
	
	
	Const QuatToEulerAccuracy# = 0.000000000001
		
	Method GetEuler:TVec3()		' using vec3 to hold eulers
		Local sint#, cost#, sinv#, cosv#, sinf#, cosf#
		Local cost_temp#
		normalise()
		sint = (2 * w * y) - (2 * x * z)
		cost_temp = 1.0 - (sint * sint)

		If Abs(cost_temp) > QuatToEulerAccuracy
			cost = Sqr(cost_temp)
		Else
			cost = 0
		EndIf

		If Abs(cost) > QuatToEulerAccuracy
			sinv = ((2 * y * z) + (2 * w * x)) / cost
			cosv = (1 - (2 * x * x) - (2 * y * y)) / cost
			sinf = ((2 * x * y) + (2 * w * z)) / cost
			cosf = (1 - (2 * y * y) - (2 * z * z)) / cost
		Else
			sinv = (2 * w * x) - (2 * y * z)
			cosv = 1 - (2 * x * x) - (2 * z * z)
			sinf = 0
			cosf = 1
		EndIf
	
		Local out:TVec3=New Tvec3		
		out.x = ATan2(sinv, cosv)
		out.y = ATan2(sint, cost)
		out.z = ATan2(sinf, cosf)
'		out.x=bound(out.x)
'		out.y=bound(out.y)
'		out.z=bound(out.z)
			
		Return out

	EndMethod
	
	Method Copy(q:TQuat)
		w=q.w
		x=q.x
		y=q.y
		z=q.z
	EndMethod
	
	
	Method FromEuler(src:TVec3)
	
		Local cr# = Cos(src.x/2)
		Local cp# = Cos(src.y/2)
		Local cy# = Cos(src.z/2)
	
		Local sr# = Sin(src.x/2)
		Local sp# = Sin(src.y/2)
		Local sy# = Sin(src.z/2)
	
		'; These variables are only here To cut down on the number of multiplications
		Local cpcy# = cp * cy
		Local spsy# = sp * sy
		Local spcy# = sp * cy
		Local cpsy# = cp * sy
	
		w = cr * cpcy + sr * spsy
		x = sr * cpcy - cr * spsy
		y = cr * spcy + sr * cpsy
		z = cr * cpsy - sr * spcy
		normalise()
	EndMethod
	
	Method Set(nw#,nx#,ny#,nz#)
		w=nw;x=nx;y=ny;z=nz
	EndMethod
	
	Method Invert()
		x=-x;y=-y;z=-z
	EndMethod 
EndType