4
\$\begingroup\$

I have been trying to learn how to use the Horde3D rendering engine for the past couple of days, and so far I have managed to learn a decent amount and integrate Bullet Physics with it as well.

My problem is in my maths for rotating and translating a node in Horde3D to keep it in sync with Bullet Physics.

I have a terrain and a sphere, both of which are in the Bullet Physics dynamics world. The sphere drops from the sky and hits the terrain and everything works fine and collides/moves around as it is supposed to.

The problem is that I can successfully translate the 3D model in Horde3D to stay in sync with the position of the sphere shape in Bullet Physics, but as soon as I try to introduce rotation things start to go wrong.

It's a bit difficult to describe so I have uploaded a video of the problem to YouTube (below). Basically, the green wireframe is the Bullet Physics sphere shape, and the brown sphere is the sphere at the Horde3D node.

Everything is fine while the sphere is falling, because there is no rotation, but as soon as it hits the terrain and rotation is supposed to take place the Horde3D node moves in a completely different direction to the Bullet Physics wireframe.

You can see what I mean by watching the video here: http://www.youtube.com/watch?v=Yi_DJIWpxOo&feature=youtu.be

I assume this is probably a quaternion/multiplication/matrix/order of multiplication error of some kind, but I can't figure it out myself.

Horde3D provides two ways that I know of to set a node's position.

They are:

h3dSetNodeTransform (http://www.horde3d.org/docs/html/_api.html#h3dSetNodeTransform)
h3dSetNodeTransMat (http://www.horde3d.org/docs/html/_api.html#h3dSetNodeTransMat)

I could use h3dSetNodeTransform and set all of the Euler angles, but Bullet Physics provides a quaternion, so I would rather try and use translation and rotation matrices instead of converting the quaternion to Euler angles etc.

For calculations I am using GLM, if that makes any difference, although I don't think it should do.

The code that handles the updating of the Horde3D node is as follows:

btTransform trans;

sphere_body->getMotionState()->getWorldTransform(trans);

// getOrigin() returns the absolute coordinates, so I am keeping
// track of them to make sure I translate the correct amount
glm::vec3 sphere_cur_pos = glm::vec3(
    trans.getOrigin().getX(),
    trans.getOrigin().getY(),
    trans.getOrigin().getZ()
);

glm::mat4 sphere_node_matrix, matrix_t, matrix_r;

const float *matrix_floats;
h3dGetNodeTransMats(sphere_node, 0, &matrix_floats);

sphere_node_matrix = glm::make_mat4(matrix_floats);

matrix_t = glm::translate(
    sphere_node_matrix,
    sphere_cur_pos - sphere_last_pos
);

// sphere_last_pos is declared earlier in the code
sphere_last_pos = sphere_cur_pos;

btQuaternion quat = trans.getRotation();

matrix_r = glm::rotate(
    matrix_t,
    quat.getAngle(),
    glm::vec3(quat.getAxis().getX(), quat.getAxis().getY(), quat.getAxis().getZ())
);

h3dSetNodeTransMat(sphere_node, glm::value_ptr(matrix_r));

The above code produces the behaviour you can see in the YouTube video.

If I remove the rotation matrix and just use:

h3dSetNodeTransMat(sphere_node, glm::value_ptr(matrix_t));

then everything works fine and the sphere node stays in sync with the Bullet Physics wireframe, but there is of course then, there is no rotation.

Can somebody point out what I am doing wrong?

If any more information is needed just let me know and I will update the question.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I managed to fix everything through a lot of experimenting.

It seems my problem came from my own misunderstanding of quaternions.

I was under the impression that they represented a change in angle, when actually they represent an orientation.

So my rotation matrix was always a bit strange because I was just pushing seemingly random values into it, directly from the quaternion provided by Bullet Physics.

I now understand that I should properly convert the quaternion to a matrix, and that would be my final rotation matrix with no further changes.

In GLM it seems that if you include:

#include <glm/gtx/quaternion.hpp>

you get given functions like glm::angleAxis which can create a quaternion in GLM from an angle and a vector. And glm::toMat4 which can do things like converting quaternions to matrices for you.

By default glm::angleAxis takes an angle in degrees not radians, so you have to do the conversion, so that's the only thing you really have to remember to do.

Anyway, here is the working code:

dynamics_world->stepSimulation(delta_time, 10);

btTransform sphere_transform;
sphere_body->getMotionState()->getWorldTransform(sphere_transform);

// Create a copy of the Bullet Physics world position in GLM
glm::vec3 sphere_world_position = glm::vec3(
    sphere_transform.getOrigin().getX(),
    sphere_transform.getOrigin().getY(),
    sphere_transform.getOrigin().getZ()
);

// Create a copy of the Bullet Physics quaternion in GLM
btQuaternion sphere_bullet_orientation = sphere_transform.getRotation();

glm::quat sphere_horde3d_orientation = glm::angleAxis(
    sphere_bullet_orientation.getAngle() * 180 / PI,
    glm::vec3(
        sphere_bullet_orientation.getAxis().getX(),
        sphere_bullet_orientation.getAxis().getY(),
        sphere_bullet_orientation.getAxis().getZ()
));

// Create a new identity translation matrix and
// use the quaternion copy to get a rotation matrix
glm::mat4 translation_matrix = glm::mat4(1.f);
glm::mat4 rotation_matrix = glm::toMat4(sphere_horde3d_orientation);

// Translate using the world position vector
translation_matrix = glm::translate(translation_matrix, sphere_world_position);

// Create the final matrix
glm::mat4 transform_matrix = translation_matrix * rotation_matrix;

h3dSetNodeTransMat(sphere_node, glm::value_ptr(transform_matrix));
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .