Decomposing glm::mat4 and setting transform to ofNode


#1

I’m trying to set an ofNode transform from another glm::mat4 object. Here’s my code:

    #include "glm/gtx/matrix_decompose.hpp"
    #include "ofNode.h"
	inline void setOfNodeTransformMatrix(ofNode * node, const glm::mat4 & m44)
	{		
		glm::vec3 scale;
		glm::quat orientation;
		glm::vec3 translation;
		glm::vec3 skew;
		glm::vec4 perspective;
		glm::decompose(m44, scale, orientation, translation, skew, perspective);
		node->setOrientation(orientation);
		node->setPosition(translation);
		node->setScale(scale);
	}

I’m ignoring skew and perspective because it’s a rigid transform. In any case, the resulting matrix has the orientation flipped on X and Y axis. And the resulting ofNode::localTransformMatrix does not match the incoming m44.

Any ideas why this may happen?

Here’s a snapshot of the method’s resulting ofNode:

image


#2

decomposing a matrix into it’s components is not completely reliable and things like this happen. you might have more luck using a simpler method since you know that your matrix contains an affine transformation (ie has no perspective)


#3

What other method can I use?


#4

there’s some other methods for decomposition where you just get the scale + rotation part of the matrix. normalizing that gives you the rotation and the magnitude is the scale. I don’t remember the details of such method though


#5

Here’s approach #2, it works well with orientation and position, but when scaling things go funky. Method #1 does tolerate scaling, but rotation seems flipped on every axis… I may go with #1 and manually flip rotation :confused:

inline void setOfNode2(ofNode * node, const glm::mat4 & m44)
{

	glm::vec3 translation;
	translation.x = m44[3][0];
	translation.y = m44[3][1];
	translation.z = m44[3][2];

	glm::vec3 scale;
	scale.x = glm::length(glm::vec3(m44[0][0], m44[0][1], m44[0][2]));
	scale.y = glm::length(glm::vec3(m44[1][0], m44[1][1], m44[1][2]));
	scale.z = glm::length(glm::vec3(m44[2][0], m44[2][1], m44[2][2]));

	glm::quat rotation;
	float rot[16] = {
		m44[0][0], m44[0][1], m44[0][2], 0,
		m44[1][0], m44[1][1], m44[1][2], 0,
		m44[2][0], m44[2][1], m44[2][2], 0,
		0, 0, 0, 1
	};

	glm::mat4 myrot = glm::make_mat4(rot);
	rotation = glm::quat_cast(myrot);

	node->setGlobalOrientation(rotation);
	node->setGlobalPosition(translation);
	node->setScale(scale);
}

#6

This does it, just had to inverse the orientation from method #1:

void setOfNodeTransformMatrix(ofNode * node, const glm::mat4 & m44)
{
	glm::vec3 scale;
	glm::quat orientation;
	glm::vec3 translation;
	glm::vec3 skew;
	glm::vec4 perspective;
	glm::decompose(m44, scale, orientation, translation, skew, perspective);

	node->setGlobalPosition(translation);
	node->setGlobalOrientation(glm::inverse(orientation));
	node->setScale(scale);
}

Only for affine transforms!


#7

in method 2 if you normalize the rotation matrix columns before converting them to a rotation that should get rid of the scale