0

I'm using my own classes and mathematical functions in C++, and I am making a dire mistake but cannot see where it is. I am representing a 4x4 matrix with a linear array, here are my matrix generator functions:

float& Mat4x4::getRef(unsigned int row, unsigned int column)
{
    return this->data[(4 * (column)) + row];
}

void Mat4x4::set(unsigned int row, unsigned int column, float value)
{
    this->getRef(row, column) = value;
}

Mat4x4 Mat4x4::getRotationalXMatrix(Vec3 rot, bool oglform)
{
    /*
        |  1  0       0       0 |
     M = |  0  cos(A) -sin(A)  0 |
         |  0  sin(A)  cos(A)  0 |
         |  0  0       0       1 |

         standard mathematical format -- opengl wants the transposed.
    */
    Mat4x4 res = Mat4x4::identity();
    res.set(1, 1, cos(rot.getX()));
    res.set(2, 1, (-sin(rot.getX())));
    res.set(1, 2, sin(rot.getX()));
    res.set(2, 2, cos(rot.getX()));
    return oglform ? res.transposed() : res;
}

Mat4x4 Mat4x4::getRotationalYMatrix(Vec3 rot, bool oglform)
{
    /*
         |  cos(A)  0   sin(A)  0 |
     M = |  0       1   0       0 |
         | -sin(A)  0   cos(A)  0 |
         |  0       0   0       1 |

         standard mathematical format -- opengl wants the transposed.
    */
    Mat4x4 res = Mat4x4::identity();
    res.set(0, 0, cos(rot.getY()));
    res.set(2, 0, sin(rot.getY()));
    res.set(0, 2, -sin(rot.getY()));
    res.set(2, 2, cos(rot.getY()));
    return oglform ? res.transposed() : res;
}

Mat4x4 Mat4x4::getRotationalZMatrix(Vec3 rot, bool oglform)
{
    /*
        |  cos(A)  -sin(A)   0   0 |
     M = |  sin(A)   cos(A)   0   0 |
         |  0        0        1   0 |
         |  0        0        0   1 |

         standard mathematical format -- opengl wants the transposed.
    */
    Mat4x4 res = Mat4x4::identity();
    res.set(0, 0, cos(rot.getZ()));
    res.set(1, 0, -sin(rot.getZ()));
    res.set(0, 1, sin(rot.getZ()));
    res.set(1, 1, cos(rot.getZ()));
    return oglform ? res.transposed() : res;
}

Mat4x4 Mat4x4::getRotationalMatrix(Vec3 pos, bool oglform)
{
    return getRotationalXMatrix(pos, oglform) * getRotationalYMatrix(pos, oglform) * getRotationalZMatrix(pos, oglform);
}

Mat4x4 Mat4x4::getTranslationMatrix(Vec3 pos, bool oglform)
{
Mat4x4 res = Mat4x4::identity();
    res.set(3, 0, pos.getX());
    res.set(3, 1, pos.getY());
    res.set(3, 2, pos.getZ());
    return oglform ? res.transposed() : res;
}

Mat4x4 Mat4x4::getScaleMatrix(Vec3 scale, bool oglform)
{
    Mat4x4 res = Mat4x4::identity();
    res.set(0, 0, scale.getX());
    res.set(1, 1, scale.getY());
    res.set(2, 2, scale.getZ());
    return oglform ? res.transposed() : res;
}

Mat4x4 Mat4x4::lookatOGL(Vec3 eye, Vec3 centre, Vec3 up)
{
    Vec3 zaxis = (centre - eye).normalised();
    Vec3 xaxis = (up.cross(zaxis)).normalised();
    Vec3 yaxis = zaxis.cross(xaxis);
    float orient[16] = {0.0f};
    orient[0] = xaxis.getX();
    orient[1] = yaxis.getX();
    orient[2] = zaxis.getX();
    orient[3] = 0.0f;

    orient[4] = xaxis.getY();
    orient[5] = yaxis.getY();
    orient[6] = zaxis.getY();
    orient[7] = 0.0f;

    orient[8] = xaxis.getZ();
    orient[9] = yaxis.getZ();
    orient[10] = zaxis.getZ();
    orient[11] = 0.0f;

    orient[12] = 0.0f; orient[13] = 0.0f; orient[14] = 0.0f; orient[15] = 1.0f;
    Mat4x4 orientation(orient);

    float trans[16] = {0.0f};

    trans[0] = 1.0f;
    trans[1] = 0.0f;
    trans[2] = 0.0f;
    trans[3] = 0.0f;
    trans[4] = 0.0f;
    trans[5] = 1.0f;
    trans[6] = 0.0f;
    trans[7] = 0.0f;
    trans[8] = 0.0f;
    trans[9] = 0.0f;
    trans[10] = 1.0f;
    trans[11] = 0.0f;
    trans[12] = -eye.getX();
    trans[13] = -eye.getY();
    trans[14] = -eye.getZ();
    trans[15] = 1.0f;

    Mat4x4 translation(trans);

    return (translation * orientation);
}

And the five important OpenGL matrices:

Mat4x4 Mat4x4::getModelMatrix(Vec3 pos, Vec3 rot, Vec3 scale, bool oglform)
{
    return Mat4x4::getTranslationMatrix(pos, oglform) * Mat4x4::getRotationalMatrix(rot, oglform) * Mat4x4::getScaleMatrix(scale, oglform);
}

Mat4x4 Mat4x4::getViewMatrix(Vec3 eye, Vec3 centre, Vec3 up, bool oglform)
{
    return Mat4x4::lookatOGL(eye, centre, up);
}

Mat4x4 Mat4x4::getProjectionMatrix(float fovRad, float aspectRatio, float near, float far, bool oglformat)
{
    float tanHalfFOV = tan(fovRad / 2);
    float data[16] = {0.0f};
    Mat4x4 res(data);
    res.set(0, 0, (1/(aspectRatio * tanHalfFOV)));
    res.set(1, 1, (1/tanHalfFOV));
    res.set(2, 3, -1);

    float twotwo = -(far + near) / (far - near);
    float threetwo = -(2 * far * near) / (far - near);
    res.set(2, 2, twotwo);
    res.set(3, 2, threetwo);
    return res;
}

Mat4x4 Mat4x4::getMVMatrixOGL(Vec3 pos, Vec3 rot, Vec3 scale, Vec3 eye, Vec3 centre, Vec3 up)
{
    Mat4x4 m = Mat4x4::getModelMatrix(pos, rot, scale, true);
    Mat4x4 v = Mat4x4::getViewMatrix(eye, centre, up, true);
    return v * m;
}

Mat4x4 Mat4x4::getMVPMatrixOGL(Vec3 pos, Vec3 rot, Vec3 scale, Vec3 eye, Vec3 centre, Vec3 up, float fovRad, float aspectRatio, float near, float far)
{
    Mat4x4 m = Mat4x4::getModelMatrix(pos, rot, scale, true);
    Mat4x4 v = Mat4x4::getViewMatrix(eye, centre, up, true);
    Mat4x4 p = Mat4x4::getProjectionMatrix(fovRad, aspectRatio, near, far, true);
    return p * v * m;
}

I see several observational issues with the resulting matrices. When the camera is very close to the model, it appears fairly normal, rotating on the y-axis as normal. However, as the camera gets further away from the model, the model rotates around the y axis in a circular fashion with an increasing radius. Also, the model appears to appear slightly flatter toward the apex of rotation, but that could be due to the nature of the view matrix?

This observation is with using the MV matrix and not the projection matrix at all. When I use an MVP matrix, things get alot worse. The model appears almost completely flat, with some vertices stretching as long as my far-clip, which is normally 1000.0f. My first thought was that I had a few transposing issues, but I know for a fact that my transposing function worked correctly. My Mat4x4 class is natively row-major, as mathematics suggests is the normal format. The oglformat booleans transpose to column major. What did I do so wrong?

Harrand
  • 355
  • 6
  • 14
  • According to [this](http://stackoverflow.com/questions/17717600/confusion-between-c-and-opengl-matrix-order-row-major-vs-column-major?rq=1) answer, the translation components have to be in the 13, 14, and 15th positions. In your code, the translation components go to 3rd, 4th, and 5th position. BTW, you are storing in collumn-major so if `oglform=false` you get collumn-major matrices, and if `oglform=true` you get row-major. – triple_r Feb 08 '16 at 20:05
  • @triple_r Thanks for the reply. This may be a misunderstanding on my own part, but both the MVPMatrix functions return the translation matrices with oglformat = true. As you said, the translation components are in the row-major format and not the column major format, which is why when oglformat is true, it is transposed, returning the correct column-major format if I am not mistaken. I am under the impression that all of my functions return a row-major format unless oglformat is true. If this is not the case, could you please tell me which ones do not return such a format? – Harrand Feb 08 '16 at 23:28
  • In `GetRef` you are returning the array index `(4 * (column)) + row`, so it means the matrix is stored in the array as `{{0,4,8,12},{1,5,9,13},{2,6,10,14},{3,7,11,15}}`, I think what you need is `{{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}}` which is `(4 * (row)) + column`. – triple_r Feb 09 '16 at 06:31
  • see [Understanding 4x4 homogenous transform matrices](http://stackoverflow.com/a/28084380/2521214) you can compare the matrices from my example program with yours to see the difference. Too lazy to analyze your code (too much of it) my bet is you are confusing local and global rotations, loosing precision of matrix with iterations (you need to ensure ortho-normality) and or misplace some projection cell positions – Spektre Mar 03 '16 at 10:11

0 Answers0