c++ - 我的矩阵堆栈实现 (OpenGL ES 2.0) 有什么问题?

标签 c++ opengl-es opengl-es-2.0 coordinate-transformation

我正在将我的 OpenGL 1.1 应用程序移植到 OpenGL ES 2.0,并且正在编写一个包装器来实现 OpenGL 1.1 功能。在我开始调用 glPushMatrix()glPopMatrix() 之前,我的代码似乎工作正常。我认为我对这些应该如何实现的理解是不正确的。

我是否在将其推回堆栈之前计算最终的旋转/平移/缩放?我应该只保留一个模型 View 矩阵(而不是将其分成三个)吗?转换应用的顺序是否正确?

这是我的转换矩阵的代码

static std::vector<GLfloat> vertices;
static std::vector<std::vector<GLfloat>> rotationMatrixStack;
static std::vector<std::vector<GLfloat>> scalingMatrixStack;

static std::vector<GLfloat> rotationMatrix =
{
    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
};

static std::vector<GLfloat> scalingMatrix =
{
    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
};

static std::vector<GLfloat> translationMatrix =
{
    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
};

static std::vector<GLfloat> orthographicMatrix =
{
    .0025f, 0.0f, 0.0f, -1.0f,
    0.0f, .0025f, 0.0f, -1.0f,
    0.0f, 0.0f, 1.0f, 0.0f,
    0.0f, 0.0f, 0.0f, 1.0f
};

void glTranslatef (GLfloat x, GLfloat y, GLfloat z)
{
    float translation[] = 
    {
        1.0f, 0.0f, 0.0f,   x,
        0.0f, 1.0f, 0.0f,   y,
        0.0f, 0.0f, 1.0f,   z,
        0.0f, 0.0f, 0.0f, 1.0f
    };

    multiplyMatrix(translation , &translationMatrix[0], &translationMatrix[0]);
}
void glScalef (GLfloat x, GLfloat y, GLfloat z)
{
    float scaling[] = 
    {
           x, 0.0f, 0.0f, 0.0f,
        0.0f,    y, 0.0f, 0.0f,
        0.0f, 0.0f,    z, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f
    };

    multiplyMatrix(scaling , &scalingMatrix[0], &scalingMatrix[0]);
}
void glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
{
    glTranslatef(-x, -y, -z);
    GLfloat radians = angle * M_PI/180;
    float zRotation[] = 
    {
        cos(radians), -sin(radians), 0.0f, 0.0f,
        sin(radians),  cos(radians), 0.0f, 0.0f,
            0.0f,          0.0f, 1.0f, 0.0f,
            0.0f,          0.0f, 0.0f, 1.0f
    };

    multiplyMatrix(zRotation , &rotationMatrix[0], &rotationMatrix[0]);
    glTranslatef(x,y,z);
}

void glLoadIdentity (void)
{
    rotationMatrix, scalingMatrix, translationMatrix = 
    {
        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
    };
}

void multiplyMatrix(float* a, float* b, float* product)
{
    int a_heigth = 4;
    int a_width = 4;
    int b_heigth = 4;
    int b_width = 4;
    int product_heigth = a_heigth;
    int product_width = b_width;

    float intermediateMatrix[product_heigth * product_width] = {0};
    for (int product_row = 0; product_row < product_heigth; product_row++)
    {
        for (int product_column = 0; product_column < product_width; product_column++)
        {
            float value = 0;
            //std::cout << "r[" << (product_row*product_width) + product_column << "] = ";
            for (int multiplication_index = 0; multiplication_index < a_width ; multiplication_index++)
            {
                value += a[(product_row * a_width) + multiplication_index] * b[product_column + (b_heigth * multiplication_index)];
                //std::cout << "( a[" << (product_row * a_width) + multiplication_index << "] * b[" << product_column + (b_heigth * multiplication_index) << "] ) + ";
            }
            //std::cout << std::endl;
            intermediateMatrix[(product_row*product_width) + product_column] = value;
        }
    }

    for (int i = 0; i < product_heigth * product_width; i++)
    {
        product[i] = intermediateMatrix[i];
    }
}

这是矩阵栈的代码

static std::vector<std::vector<GLfloat>> translationMatrixStack;
void glPushMatrix()
{
    rotationMatrixStack.push_back(rotationMatrix);
    scalingMatrixStack.push_back(scalingMatrix);
    translationMatrixStack.push_back(translationMatrix);
}

void glPopMatrix()
{
    rotationMatrix = rotationMatrixStack.back();
    scalingMatrix = scalingMatrixStack.back();
    translationMatrix = translationMatrixStack.back();

    rotationMatrixStack.pop_back();
    scalingMatrixStack.pop_back();
    translationMatrix.pop_back();
}

这是顶点着色器代码

attribute highp vec4    myVertex;
uniform mediump mat4    orthographicMatrix;
uniform mediump mat4    translationMatrix;
uniform mediump mat4    scalingMatrix;
uniform mediump mat4    rotationMatrix;
void main(void)
{
    gl_Position =   orthographicMatrix * translationMatrix * scalingMatrix * rotationMatrix * ( myVertex) ;
}";

最佳答案

您没有用于旋转、平移和缩放的单独矩阵堆栈。在 OpenGL 中,每种矩阵模式都有一个矩阵堆栈(参见 glMatrixMode)。矩阵模式是 GL_MODELVIEWGL_PROJECTIONGL_TEXTURE


请参阅 glTranslate 的文档:

glTranslate produces a translation by x y z . The current matrix (see glMatrixMode) is multiplied by this translation matrix, with the product replacing the current matrix.

glRotate 的文档:

glRotate produces a rotation of angle degrees around the vector x y z . The current matrix (see glMatrixMode) is multiplied by a rotation matrix with the product replacing the current matrix.

glScale 的文档:

glScaleproduces a nonuniform scaling along the x, y, and z axes. The three parameters indicate the desired scale factor along each of the three axes. The current matrix (see glMatrixMode) is multiplied by this scale matrix.


这意味着您需要一个矩阵堆栈,并且所有操作都在同一个矩阵堆栈上进行。

请注意,矩阵乘法 C = A * B 的工作原理如下:

Matrix4x4 A, B, C;

// C = A * B
for ( int k = 0; k < 4; ++ k )
    for ( int j = 0; j < 4; ++ j )
        C[k][j] = A[0][l] * B[k][0] + A[1][j] * B[k][1] + A[2][j] * B[k][2] +  A[3][j] * B[k][3];


一个 4*4 矩阵看起来像这样:

  c0  c1  c2  c3            c0  c1  c2  c3
[ Xx  Yx  Zx  Tx ]        [  0   4   8  12 ]     
[ Xy  Yy  Zy  Ty ]        [  1   5   9  13 ]     
[ Xz  Yz  Zz  Tz ]        [  2   6  10  14 ]     
[  0   0   0   1 ]        [  3   7  11  15 ] 

而一个 4*4 矩阵的内存图像是这样的:

[ Xx, Xy, Xz, 0, Yx, Yy, Yz, 0, Zx, Zy, Zz, 0, Tx, Ty, Tz, 1 ]


这意味着您必须调整矩阵操作:

static std::vector<std::vector<GLfloat>> modelViewMatrixStack;

static std::vector<GLfloat> modelViewMatrix{
    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 };

void multiplyMatrix( float A[], float B[], float P[] )
{
    float C[16];
    for ( int k = 0; k < 4; ++ k ) {
        for ( int l = 0; l < 4; ++ l ) {
            C[k*4+j] =
                A[0*4+j] * B[k*4+0] +
                A[1*4+j] * B[k*4+1] +
                A[2*4+j] * B[k*4+2] +
                A[3*4+j] * B[k*4+3];
        }
    }
    std::copy(C, C+16, P);
}

void glTranslatef( GLfloat x, GLfloat y, GLfloat z )
{
    float translation[]{
        1.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 1.0f, 0.0f,
        x,    y,    z,    1.0f };

    multiplyMatrix(&modelViewMatrix[0], translation, &modelViewMatrix[0]);
}

void glScalef( GLfloat x, GLfloat y, GLfloat z )
{
    float scaling[]{
        x,    0.0f, 0.0f, 0.0f,
        0.0f, y,    0.0f, 0.0f,
        0.0f, 0.0f, z,    0.0f,
        0.0f, 0.0f, 0.0f, 1.0f };

    multiplyMatrix(&modelViewMatrix[0], scaling, &modelViewMatrix[0]);
}

void glRotatef( GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
{
    float radians = angle * M_PI/180;
    float c = cos(radians);
    float s = sin(radians);

    float rotation[16]{
       x*x*(1.0f-c)+c,   x*y*(1.0f-c)-z*s, x*z*(1.0f-c)+y*s, 0.0f,
       y*x*(1.0f-c)+z*s, y*y*(1.0f-c)+c,   y*z*(1.0f-c)-x*s, 0.0f,
       z*x*(1.0f-c)-y*s  z*y*(1.0f-c)+x*s, z*z*(1.0f-c)+c,   0.0f,
       0.0f,             0.0f,             0.0f,             1.0f };

    multiplyMatrix(&rotationMatrix[0], rotation, &rotationMatrix[0]);
}  


进一步查看:

关于c++ - 我的矩阵堆栈实现 (OpenGL ES 2.0) 有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46732918/

相关文章:

c++ - 使用函数指针作为回调

iphone - 在 glDrawArrays() 上调试 SIGKILL。苹果手机

ios - OpenGL 矩阵变换的一场革命

android - QOpenGLWidget 不绘制数组

android - 绘制到 FrameBuffer 会导致 Y 反转

c++ - 如何在没有源代码的 tcp 服务器应用程序中查找错误

c++ - SOIL 连接不正确

c++ - 在哪里可以找到有关嵌入式 C++ 的信息?

Android glShaderBinary

java - Triangle_Strip 应该包裹吗?