Physics simulation demo with ODE and Blender


(Devas73) #1

With regard to my previous post about extracting euler angles from the rotation matrix, it appears to be a highly ill conditioned mathematical problem, for which I found an approximated solution on Googles.
If you’re curious you can take a look at this movie (600Kb) where you can see how the rotation is screwed at the end of the animation, probably because of numerical errors:

http://members.xoom.it/Devas/0001_0250.avi

If only Blender had quaternions or rotation matrix writable…
I will try to solve this problem, if anyone has found a working solution please let me know.


(S68) #2

Hi,

well, euler matrix should contain the components of the unit vectors of one reference system in the other reference system, isn’t it?

I don’t think that is ill conditioned.

If you have more details on the exact format of euler’s matrix in Blender I think we can came out with a nice solution

Stefano

P.S. where is the problem in your avi? Except that the cube goes inside the plane, I mean…


(Devas73) #3

Hi Stefano, we could speak italian but it’s best to use my weak english for the rest of the blender maniacs : )
The problem of, given the rotation matrix, find the Euler angles, is ill conditioned because there is not a unique solution, and discontinuities can show as well as problems with the infamous “gimbal lock”.
From what I recall from my university studies in linear algebra and geometry, the problem is not of simple solution, I had to take a look in the newsgroups, where aerospace dedicated discussion groups shed a bit of light.
I tried an algorithm I found on the NG, but in the rest position, as you can see, the “brick” should lie with the same orientation of the plane (it penetrates probably because of geometry alignment problems: the collision detection is performed by ODE on the geometry I specified in the C dll imported in python, and if this geometry differs from the Blender one it will look as if the brick penetrates into the plane - this puzzles me a bit because I was careful into aligning the two… I still need to investigate on this) while the animation shows that it rest with an angle different from zero.
The same simulation performed in OpenGL real time gives no problem.
This is why I think it’s a problem with the conversion function, even if I don’t have the deep knowledge required to analyse what’s wrong with it.
This is what I found: given the matrix M,
a. psi := atan2(M[0][1], M[0][0])
b. Compute a new 3x3 matrix: M1 := M *
{ { cos(psi), -sin(psi),0 },
sin(psi), cos(psi), 0 },
{ 0, 0, 1 } }.
c. theta := atan2(-M1[0][2], M1[0][0])
d. M2 := M1 * { { cos(theta), 0, sin(theta) }, { 0, 1, 0 },-sin(theta), 0, cos(theta) } }
e. phi := atan2(M2[1][2], M2[1][1])

Phew!
Anyway, I’ll make more experiments this evening.


(eeshlo) #4

You are obviously progressing nicely!
Anyway here is a function that I use without problems sofar, adapted from the matrix/quaternion faq,
In python:


def mat2euler(mat, size):
    scale = [0.0, 0.0, 0.0]
    if size[0]!=0.0: scale[0] = 1.0/size[0]
    if size[1]!=0.0: scale[1] = 1.0/size[1]
    if size[2]!=0.0: scale[2] = 1.0/size[2]
    angle_y = -asin(mat[0][2] * scale[0])
    C = cos(angle_y)
    if abs(angle_y)>1.0e-10:
        C = 1.0/C
        angle_x = atan2((mat[1][2] * scale[1]) * C, (mat[2][2] * scale[2]) * C) 
        angle_z = atan2((mat[0][1] * scale[0]) * C, (mat[0][0] * scale[0]) * C)
    else:
        angle_x = 0.0
        angle_z = -atan2((mat[1][0] * scale[1]), (mat[1][1] * scale[1]))
    return (angle_x, angle_y, angle_z)

(edited to remove scaling from matrix)
You only need to pass the matrix from the object you get from Blender and it returns a tuple of three angles in radians.
You can test it on two objects in Blender, by copying the rotation, like this:
ob2.rot = mat2euler(ob1.mat, ob1.size)

But it is generally adivised to not use euler angles but quaternions instead. You could try converting the matrix to quaternion and the quaternion to euler, but I’m not sure if that would be any better…


(Devas73) #5

Hi Eeshlo, thanks for your reply.
I will try your code this evening.
I’m using euler angles because Blender doesn’t allow to set the object matrix, it’s a read only parameter.
Only RotX,RotY and Rotz can be set.
The simulation library (which has been set up for a matching geometrical scene) performs a sim step, returning the position (a vector) and rotation (a matrix or a quaternion) to apply to the blender object.
I searched in the NG if there is any better conversion from quaternion to euler, but everything I found make an intermediate conversion matrix…


(Devas73) #6

I just discovered there was an error in the C code (a rotation instruction that slipped) that added an offset to all rotations! Anyway the code from eeshlo works better, thanks!
Now I have everything working correctly.
I plan to make a user friendly tool with all this, but this will take a lot of time.
It will be possible to create a scene, specify which objects will participate in the simulation, specify their collision shapes, their physical attributes and mechanical joints.


(eeshlo) #7

If you need a direct quaternion to euler conversion, I have code for that too, in case you need that.
I have succesfully tested it for instance with armature movements, converting it to Blender object euler rotations.


(blendedHKU) #8

WOW this function really works great!!!

I’m trying to make a euler2mat function but I can’t seem to make it work,
can anyone help me, post something, it shouldn’t be that hard.


(eeshlo) #9

I’m not sure what you mean, if you can’t get it to work, how do you know it works great? Anyway, I edited the message so it looks more like real code, and if that doesn’t help, there is a function in the Lightflow export script which will get all info from a blender matrix like rotation, scaling and translation. Look for a function called ‘infoFromMtx’. The code above might actually give a wrong result in some cases. The one from the Lightflow script seems to work better.


(blendedHKU) #10

Hi Eeshlo,

What i mean is: your script works great, I got it to work, and it does exactly what it should do.

What I wanted to ask was if you could write a script that does the reverse (not extracting euler angles from a matrix, but generating a matrix out of euler angles)

So that i can not only read how many degrees an object is rotated, but i can also SET the rotation of an object.

Thnx again,

Jasper


(eeshlo) #11

You can’t change the blender matrix, it is read only, if that is what you wanted to do. But in any case here is a some code from what is used in Dynamica, this gets you 3x3 rotation matrix for the specified axis:


# creates rotation matrix around X, Y or Z
# axis must be 'X', 'Y' or anything else=='Z'
# angle in radians, all made equivalent to blenders matrices from RotXYZ
def makeRotMtx(axis, angle):
	if axis=='X':	
		rs, rc = sin(angle), cos(angle)
		mtx = [	[1.0, 0.0, 0.0],
			[0.0,  rc, rs],
			[0.0, -rs, rc] ]
	elif axis=='Y':
		rs, rc = sin(angle), cos(angle)
		mtx = [	[ rc, 0.0, -rs],
			[0.0, 1.0, 0.0],
			[ rs, 0.0,  rc] ]
	else:
		rs, rc = sin(angle), cos(angle)
		mtx = [	[ rc,  rs, 0.0],
			[-rs,  rc, 0.0],
			[0.0, 0.0, 1.0] ]
	return mtx

If you want to rotate all three in one go, you could use the above function to create 3 matrices and multiply them, but instead it is much faster to use this optimized function:


# creates full 3D rotation matrix
# rx, ry, rz angles in radians
def makeRotMtx3D(rx, ry, rz):
	A, B = sin(rx), cos(rx)
	C, D = sin(ry), cos(ry)
	E, F = sin(rz), cos(rz)
	AC, BC = A*C, B*C
	return [[D*F,   D*E, -C],
		[AC*F-B*E, AC*E+B*F, A*D],
		[BC*F+A*E, BC*E-A*F, B*D]]

But like I said, all these are no use if you want to change the Blender matrix, that can’t be done. Although you could use it in GameBlender with setOrientation maybe, but I’m not sure if you actually get the correct orientation. I changed everything so I would get consistent results with what Blender’s matrices would return when changing RotX/Y/Z. I don’t know if the game engine is different.


(blendedHKU) #12

Hi Eeshlo thanks for the script. This was exactly what I wass looking for…

These posts might have been confusing, but i didn’t realize that this thread is in the python & plugins section.

I use your scripts in the gameEngine.

It allows you to directly set and get the rotation of objects.
The only way to do this in Blender is to use the owner.getOrientation()/setOrientation() functions and they return these darn matrixes.

now you can say:

angles = mat2euler(owner.getOrientation())

to get rotation of objects, and

owner.setOrientation(euler2mat(angles))

to set rotation

Jasper