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

时间:2017-10-13 15:06:56

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

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

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

这是我的转换矩阵的代码

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) ;
}";

1 个答案:

答案 0 :(得分:1)

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


请参阅glTranslate的文档:

  

glTranslatex y z生成翻译。当前矩阵(参见glMatrixMode)乘以此平移矩阵,产品替换当前矩阵。

glRotate的文档:

  

glRotate围绕向量x y z产生角度旋转。当前矩阵(参见glMatrixMode)乘以旋转矩阵,产品替换当前矩阵。

以及glScale的文档:

  

glScale会在xyz轴上产生不均匀的缩放。这三个参数表示沿三个轴中的每个轴的所需比例因子。   当前矩阵(参见glMatrixMode)乘以该比例矩阵。


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

注意,矩阵乘法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]);
}  


进一步了解: