【问题标题】:What is wrong with my matrix stack implementation (OpenGL ES 2.0)?我的矩阵堆栈实现(OpenGL ES 2.0)有什么问题?
【发布时间】:2017-10-13 15:06:55
【问题描述】:

我正在将我的 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) ;
}";

【问题讨论】:

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


    【解决方案1】:

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


    glTranslate的文档:

    glTranslate 通过x 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]);
    }  
    


    进一步看:

    【讨论】:

    • 执行此操作时,我的一些工作 OpenGL 代码会失真。无论用户调用函数的顺序如何,OpenGL 似乎都会按照旋转 -> 缩放 -> 平移的顺序应用变换。使用一个模型视图矩阵,我如何仍然保证这个顺序来保持这种行为?
    • 我认为我需要按列主要顺序完成所有矩阵数学运算:stackoverflow.com/questions/15993339/…
    • 在coIumn主要顺序中,着色器的正确顺序仍然是gl_Position = orthographicMatrix * modelViewMatrix * myVertex
    • @j_omega 是的,是gl_Position = projectionMatrix * modelViewMatrix * vec4(pos.xyz, 1.0);
    猜你喜欢
    • 1970-01-01
    • 2011-10-02
    • 1970-01-01
    • 1970-01-01
    • 2013-09-30
    • 1970-01-01
    • 1970-01-01
    • 2017-09-16
    • 2013-03-28
    相关资源
    最近更新 更多