2
votes

I'm trying to construct a 3D OBB for a plane shape, by using a list of 4 points, like so:

    glm::vec3 = plane.getPosition();
    glm::vec3 points[ 4 ]={ 
        p+glm::vec3( -c->getWidth()*0.5f,0.0f,-c->getLength()*0.5f), //left front
        p+glm::vec3(-c->getWidth()*0.5f,0.0f,c->getLength()*0.5f),  //left back
        p+glm::vec3( c->getWidth()*0.5f,0.0f,-c->getLength()*0.5f),   //right front
        p+glm::vec3( c->getWidth()*0.5f,0.0f,c->getLength()*0.5f),  //right back

Which works fine. However, rotating the points to the orientation of the object the shape represents is proving difficult, as the mat4 transform contains scaling information, which magnifies the dimensions of the box, causing innacuracy in the collision detection system.

What is the best way to extract a 3x3 transform matrix from the original mat4 transform matrix, leaving behind the translation and scale?

1

1 Answers

0
votes

To remove scale from matrix you must store the information about scaling at some sort of vector.

Mcurr = Mscale * Mprev

Mscale_inv = Mscale^(-1)

Mprev2 = Mscale_inv * Mcurr 

Than using this vector build the original scale matrix and invert it. Than multiply it to the matrix you have, and you will get the matrix without scaling you did not want to have.

Mprev = {{ X, X, X, Y },
         { X, X, X, Y },
         { X, X, X, Y },
         { Y, Y, Y, Y }};

The translation values not hard to remove just use first 3 rows and 3 columns of homogeneous matrix you get. The preudocode above displays 'X' the values of matrix we to get for building our rotation only matrix.

Here i post code to display scale removing on my own linear algebra library (sorry cannot display on glm donot have it but I am sure there is methods to do it with glm):

float identity[] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };

float scale[] = {
2.0f, 0.0f, 0.0f, 0.0f,
0.0f, 2.0f, 0.0f, 0.0f,
0.0f, 0.0f, 2.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };

Common::Math::CMatrix4X4 identityM(identity);
std::cout << "Original matrix:\n" << identityM << std::endl;

Common::Math::CMatrix4X4 scaleM(scale);
std::cout << "Scale matrix:\n" << identityM << std::endl;

identityM.RotateX(30);
std::cout << "Rotated original matrix:\n" << identityM << std::endl;

Common::Math::CMatrix4X4 currentM = scaleM * identityM;
std::cout << "Current matrix:\n" << currentM << std::endl;

Common::Math::CMatrix4X4 previousM = scaleM.GetInversed() * currentM;
std::cout << "Result matrix:\n" << previousM << std::endl;

The results:

enter image description here

This case can eliminate every affine manipulation with your matrix not only scaling but rotation and translation too. But there is more faster method but only works with scale transformation.

Reduce matrix to 3x3 size removing last row/column than normalize each row or column of the result matrix (in this case you didnot have to store scale value vector):

float identity[] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };

float scale[] = {
2.0f, 0.0f, 0.0f, 0.0f,
0.0f, 2.0f, 0.0f, 0.0f,
0.0f, 0.0f, 2.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };

Common::Math::CMatrix4X4 identityM(identity);
std::cout << "Original matrix:\n" << identityM << std::endl;

Common::Math::CMatrix4X4 scaleM(scale);
std::cout << "Scale matrix:\n" << scaleM << std::endl;

identityM.RotateX(30);
std::cout << "Rotated original matrix:\n" << identityM << std::endl;

Common::Math::CMatrix4X4 currentM = scaleM * identityM;
std::cout << "Current matrix:\n" << currentM << std::endl;

Common::Math::CMatrix3X3 rcurrentM(currentM);
std::cout << "Reduced current matrix:\n" << rcurrentM << std::endl;

// normalizing each row
rcurrentM[0].Normalize();
rcurrentM[1].Normalize();
rcurrentM[2].Normalize();

std::cout << "Result matrix:\n" << rcurrentM << std::endl;

The result: enter image description here