PDA

View Full Version : How to rotate a local oriented object by the global lookat axis?



RaenirSalazar
10-26-2016, 03:13 PM
For example, in blender, I have a rigged mesh where each bone has a local orientation.

However when I rotate the bone imported to an OpenGL application for Skinning/Animations, if I do glm::rotate(angle, axis); the rotation is along it's "local" axis from within Blender, and not according to the "global" Z axis of my View.

Using glm, how would I rotate it so it appears to be rotating about an orthogonal point in my screen instead of about it's local axis?

Does this make sense?

Example:

http://i.imgur.com/ugCqsyw.png

In red, is a rotation I "want", it just happens that the original roll of the Head bone is oriented so it "appears" correct, but if I were to rotate the Mesh then obviously the bone will not rotate in the correct way as it is still rotating along it's local z.

The arm bone in yellowish green, rotates along it's local z as well.

Basically I would want the arm rotation, to be like the head rotation. Facing the camera.



glm::mat4 CurrentNodeTransform;
CopyaiMat(&this->getScene()->mRootNode->FindNode(boneName.c_str())->mTransformation, CurrentNodeTransform);

//glm::mat4 newRotation = glm::rotate(angle, glm::vec3(axis.x, axis.y, axis.z));
glm::mat4 newRotation = glm::rotate(angle, glm::vec3(0.0, 0.0, 1.0));

// NEED GLOBAL ROTATION
//CurrentNodeTransform = newRotation * CurrentNodeTransform;
CurrentNodeTransform = (CurrentNodeTransform * newRotation);

CopyGlMatToAiMat(CurrentNodeTransform, this->getScene()->mRootNode->FindNode(boneName.c_str())->mTransformation);


Basically I fetch the local rotation of the joint, rotate it, and apply it back to the heirarchy of the rig.

How would I get it so it matches the axis of the "View"?

GClements
10-26-2016, 07:31 PM
Using glm, how would I rotate it so it appears to be rotating about an orthogonal point in my screen instead of about it's local axis?

Obtain the transformation from bone space to view space (i.e. the view transformation multiplied by the global bone transformation). Invert it to get the transformation from view space to bone space. Transform the vector (0,0,1,0) by the inverse to get the bone-space rotation axis.

RaenirSalazar
10-27-2016, 10:37 AM
I tried this:



glm::mat4 BoneToView = View * CurrentNodeTransform;
glm::mat4 BoneToViewInverse = glm::inverse(BoneToView);
glm::vec4 BoneSpaceRotationAxis = BoneToViewInverse * glm::vec4(0, 0, 1, 0);
glm::mat4 newRotation = glm::rotate(angle, glm::vec3(BoneSpaceRotationAxis));

CurrentNodeTransform = CurrentNodeTransform * newRotation;


And doesn't appear to work, I'll swap around the multiplications in case I got the order wrong. Did you mean something else by "Transform the vector (0,0,1,0) by the inverse to get the bone-space rotation axis." then multiplying it?

e: For example trying to rotate the Leg; I get {0, -0.99, 0.1} (rounding down slightly) as the resulting axis of rotation, but still appears to rotate about it's Y axis, do I need to normalize it?

Oh and just in case I'll also go and reexport my model in case I was playing with the Bone rolls.

result:

http://i.imgur.com/US65Nuq.png
The rotations still seem relative to their Y (lengthwise) axis.

RaenirSalazar
10-27-2016, 10:51 AM
http://i.imgur.com/u6TFFpr.png
This is with glm::vec4(0, 1, 0, 0); as the vector I am multiplying BoneToViewInverse by.

Circles are if it's rotating as though it were facing the screen, lines otherwise to show that its rotating about that line.

RaenirSalazar
10-27-2016, 03:48 PM
Got it.



glm::mat4 LocalNodeTransform;
glm::mat4 GlobalNodeTransform;
CopyaiMat(&this->getScene()->mRootNode->FindNode(boneName.c_str())
->mTransformation, LocalNodeTransform);
FindBone(boneName, this->getScene()->mRootNode, glm::mat4(1.0), GlobalNodeTransform);
//glm::mat4 newRotation = glm::rotate(angle, glm::vec3(axis.x, axis.y, axis.z));


glm::mat4 View = glm::lookAt(
glm::vec3(0, 0, 1), // Camera in World Space
glm::vec3(0, 0, 0), // and looks at
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);

// NEED GLOBAL ROTATION
//CurrentNodeTransform = newRotation * CurrentNodeTransform;
//CurrentNodeTransform = (CurrentNodeTransform * newRotation);

glm::mat4 BoneToView = GlobalNodeTransform * View;
glm::mat4 BoneToViewInverse = glm::inverse(BoneToView);
glm::vec4 BoneSpaceRotationAxis = BoneToViewInverse * glm::vec4(0, 0, 1, 0);
printf("Printing BoneSpaceRotationAxis");
PrintVector3(glm::normalize(BoneSpaceRotationAxis) );
glm::mat4 newRotation = glm::rotate(angle,
glm::normalize(glm::vec3(BoneSpaceRotationAxis)));

LocalNodeTransform = LocalNodeTransform * newRotation;

CopyGlMatToAiMat(LocalNodeTransform, this->getScene()->mRootNode->
FindNode(boneName.c_str())->mTransformation);


Somehow I screwed up that second to last line.