Implementing Quaternions

BlitzMax Forums/MiniB3D Module/Implementing Quaternions

JoshK(Posted 2007) [#1]
I am going to be working on adding quaternions rotation today. I am also working with the modelview matrix scaled 0,0,-1 after the camera is oriented, because this eliminates the need for flipped positions, and gets rid of a lot of wackiness.

I'll be on MSN under ___________, if anyone with a good knowledge of this is available. I have done quat -> mat and back before, but it is still going to be tricky.

I'll post whatever I come up with, so you can use it with minib3d or whatever.


JoshK(Posted 2007) [#2]
Okay, my quat code worked right off the bat. Run this in Blitz3D and you will see it produces identical results:


Now added additional matrix rotation methods based on quaternions:



JoshK(Posted 2007) [#3]
Okay, it seems to work when you find every instance of -rx or -z and don't flip them. The only thing I am not sure how to do is retrieve the global quaternion.

I've got it pretty close here, which shows how to extract a quat from a mat, but the signs get flipped randomly:



JoshK(Posted 2007) [#4]
Well, I have been trying all day, and I can't get this to work right. Without proper rotation, animation is impossible.


DJWoodgate(Posted 2007) [#5]
Would it be worth looking at Blit3d's Geometry code that Mark posted as a sticky in the Blitz3d programming forum?


JoshK(Posted 2007) [#6]
DAMN I finally got it working.

I parented one mesh to another and randomly spun the parent around on the screen. When I click the mouse, the child mesh gets parented to either the center mesh or the world. When I change the parenting, the mesh stays perfectly in place, no matter what crazy angle is happening. Here, see for yourself:
http://www.leadwerks.com/post/quat.zip

It will take some time to clean this up, but the hard part is done. I'm going to go drink now.

This extracts a quaternion from a matrix:
	Method ExtractQuat()
		fourWSquaredMinus1:Float = +grid[0,0]+grid[1,1]+grid[2,2]
		fourXSquaredMinus1:Float = +grid[0,0]-grid[1,1]-grid[2,2]
		fourYSquaredMinus1:Float = +grid[1,1]-grid[0,0]-grid[2,2]
		fourZSquaredMinus1:Float = +grid[2,2]-grid[0,0]-grid[1,1]

		biggestIndex=0
		fourBiggestSquaredMinus1:Float=fourWSquaredMinus1
		If fourXSquaredMinus1 > fourBiggestSquaredMinus1
			fourBiggestSquaredMinus1 = fourXSquaredMinus1 
			biggestIndex=1
		EndIf
		If fourYSquaredMinus1 > fourBiggestSquaredMinus1
			fourBiggestSquaredMinus1 = fourYSquaredMinus1 
			biggestIndex=2
		EndIf
		If fourZSquaredMinus1 > fourBiggestSquaredMinus1
			fourBiggestSquaredMinus1 = fourZSquaredMinus1 
			biggestIndex=3
		EndIf

		biggestValue:Float=Sqr(fourBiggestSquaredMinus1+1.0)*0.5
		mult:Float=0.25/biggestValue

		Select BiggestIndex
			Case 0
				w#=BiggestValue
				x#=(grid[1,2]-grid[2,1])*mult
				y#=-(grid[2,0]-grid[0,2])*mult
				z#=-(grid[0,1]-grid[1,0])*mult
			Case 1
				x#=-BiggestValue
				w#=-(grid[1,2]-grid[2,1])*mult
				y#=(grid[0,1]+grid(1,0))*mult
				z#=(grid[2,0]+grid[0,2])*mult
			Case 2
				y#=BiggestValue
				w#=-(grid[2,0]-grid[0,2])*mult
				x#=-(grid[0,1]+grid(1,0))*mult
				z#=(grid[1,2]+grid[2,1])*mult
			Case 3
				z#=-BiggestValue
				w#=(grid[0,1]-grid(1,0))*mult
				x#=(grid[2,0]+grid[0,2])*mult
				y#=-(grid[1,2]+grid[2,1])*mult
		EndSelect

		If w<-0.0
			x=-x
			y=-y
			z=-z
			w=-w
		EndIf

		VECTOR_X=z
		VECTOR_Y=x
		VECTOR_Z=y
		VECTOR_W=w		
	EndMethod



Wayne(Posted 2007) [#7]
Damn fine work, I'm fixing a drink in your honor.


JoshK(Posted 2007) [#8]
Scale is very hard to work into this. I might just let that go, since the only reason you would need it is if you are writing a mesh editor.

If one of the main programmers of this wants to email me, I will give you as much code and info as I can. I don't really want to put together a patch, because there are a lot of extra entities and things in MiniB3D I don't want to mess with.

One of the main changes I made was flipping the Z-axis, so positions and rotations can be stored with their true values, and the original triangle order is right. However, a lot of code was written on top of a faulty foundation, and it all needs to be fixed to work right. You vertex positions and normals will be reversed now, because they are being rendered the same as in Blitz3D.



Anyone know how to extract the scale from a rotated matrix? I thought I could just get the magnitude of each row, but that doesn't account for rotation.


simonh(Posted 2007) [#9]
Personally I wouldn't bother struggling with this. I'm not sure it's worth the effort - all you're gaining is a slightly more robust EntityParent and the potential for a better TurnEntity (if implemented).

Otherwise, there are no benefits, as MinB3D works the same as Blitz3D in all other areas as far as I'm aware. Also, the aformentioned issues will be fixed at some point.


Bobysait(Posted 2007) [#10]
I think it's a great idea using quaternions !
It permits lots of things like easy PointEntity, AlignToVector or Slerp functions...
It also reduces operators from 45 for matrix rotations to 28 for quaternions

Other :
Try to make a TurnEntity local using matrix... using quaternions, it's easy as qf=q0*qd ( where qf is the final rotation, q0 is the initial one, and qd is the delta rotation )

I think MiniB3d has implemented matrix, but no support for quat, and that's a big problem. you can't optimise calculs anymore, and no ability to have better entity system.
That's the reason why I finally attempt to do my own engine+wrapper.

What i don't understand is :
@SimonH
=> you released the bmax maths library, translated from mark's code... why don't you use it instead of matrix bases ?


Leon Drake(Posted 2007) [#11]
does it still work using fitmesh?


*(Posted 2007) [#12]
strange the turnentity function I posted on the forum works with what im using it for and still allows all the commands to work perfectly (Even my testers have tested it fine).