Opengl es 手动复制总账矩阵操作的顺序

Opengl es 手动复制总账矩阵操作的顺序,opengl-es,linear-algebra,Opengl Es,Linear Algebra,我正在将一个玩具GL ES 1.1代码库移植到GL ES 2.0。没有内置的modelview矩阵操作,因此我尝试用4x4“当前矩阵”上的操作替换glScalef,glTranslatef,glRotatef调用 然而,我的矩阵数学有点粗略,乘法顺序和行与列的主要符号等都有问题,如果有人能快速概括出我应该在这里介绍的语义,我会很高兴的 例如,假设我从一个单位矩阵开始,然后(在ES 1.1代码中)按顺序执行: glTranslate(A); glRotate(B); glTranslate(C);

我正在将一个玩具GL ES 1.1代码库移植到GL ES 2.0。没有内置的modelview矩阵操作,因此我尝试用4x4“当前矩阵”上的操作替换
glScalef
glTranslatef
glRotatef
调用

然而,我的矩阵数学有点粗略,乘法顺序和行与列的主要符号等都有问题,如果有人能快速概括出我应该在这里介绍的语义,我会很高兴的

例如,假设我从一个单位矩阵开始,然后(在ES 1.1代码中)按顺序执行:

glTranslate(A);
glRotate(B);
glTranslate(C);
。。。我需要在“当前矩阵”上做什么数学运算才能在发送给着色器的最终modelview矩阵中复制此功能?我试着保留一个矩阵,对于每个操作,生成一个表示它的新矩阵,并将其乘以当前矩阵。结果是不正确的,我想在乘法前/乘法后,还有一些我不明白的地方,-主要的,等等

有人愿意在这里就这个理论说几句话吗?谢谢(在使其超高效之前,我想先了解基本知识。)

(这是:
问了一个类似的问题,但答案谈到了如何提高效率,并没有真正启发我数学上的等价性。)

基本上,您正在寻找opengl矩阵堆栈的替代品来进行转换

假设您使用的是c/c++,我建议您看看GLM库:

它是一个只包含标题的库,易于使用,是opengl es 2.0之前矩阵堆栈的完美替代品。它甚至为不推荐使用的glu函数提供了功能,如gluOrtho()和gluPerspective()。Glm的矩阵可以很容易地传递给着色器,因为它们是在考虑着色器的情况下构思的

您必须对代码进行一些更改;例如,将自己的顶点/矩阵定义转换为glm::vec3/glm::mat4

下面是一个如何构造传递给顶点着色器的mvp矩阵的示例:在本例中,actorInstance类有一些属性,如位置(在世界中)和旋转,定义为glm::vec3。构造的模型、模型/视图和模型/视图/投影矩阵都是该类的属性:

void CActorInstance::update(glm::mat4 viewMatrix, glm::mat4 projectionMatrix)
{

    // act according to class behavior
    this->actorClass->act(&input, &world, &direction, &rotation);

    // calculate the translation matrix
    glm::mat4 translate = glm::mat4();
    translate = glm::translate( glm::mat4(), world);

    // calculate the rotation matrix   
    glm::mat4 rotateX = glm::rotate( glm::mat4(1.0f), rotation.x, glm::vec3(1,0,0));
    glm::mat4 rotateY = glm::rotate( glm::mat4(1.0f), rotation.y, glm::vec3(0,1,0));
    glm::mat4 rotateZ = glm::rotate( glm::mat4(1.0f), rotation.z, glm::vec3(0,0,1));
    glm::mat4 rotate = rotateX * rotateY * rotateZ;

    // calculate the model matrix
    mMatrix = translate * rotate;

    // calculate the model/view matrix
    mvMatrix = viewMatrix * mMatrix;

    // calculate the model/view/projection matrix
    mvpMatrix = projectionMatrix * mvMatrix;
};
显然,每个对象的mvp矩阵在每一帧都会根据对象的位置和旋转进行更新。viewMatrix和projectionMatrix是从我的camera类传下来的。 然后使用该矩阵渲染网格:

    void CMesh::renderMesh(GLuint program, glm::mat4 *mvp)
    {
        glUseProgram(program);

        int mvpLocation = glGetUniformLocation(program, "mvpMatrix");
        int texLocation = glGetUniformLocation(program, "baseMap");
        glUniformMatrix4fv( mvpLocation, 1, GL_FALSE, glm::value_ptr(*mvp));

// rendering code ommitted


    };
希望这有帮助:)

编辑:实施矩阵堆栈的建议

stl::stack<glm::mat4> matrixStack; // the matrix stack
matrixStack.push_back(glm::mat4()); // push an identity matrix on the stack
stl::stack matrixStack;//矩阵堆栈
matrixStack.push_back(glm::mat4());//将标识矩阵推送到堆栈上
这就是您的glLoadIdentity()

我试着保留一个矩阵,对于每一个操作,都会创建一个新的矩阵 表示它的矩阵,并将其乘以当前值

嗯,事情就是这样做的。没什么特别的

调用和(当然还有,和)的相应矩阵非常容易构造,如链接中所示

您只需将当前矩阵
M
上相应的变换矩阵
T
右乘即可:

M' = M * T
因为我们(或您要复制的旧OpenGL)希望在绘制之前调用的最后一个转换首先应用于对象


然后,您还必须与矩阵的存储保持一致(行主对列主),无论您选择哪一个。但由于您使用的是OpenGL,列主存储将是一个好主意,因为它可以让您更轻松地将它们上载到GLSL(不过,与转置标志无关),可以更好地使用矢量化SIMD指令(如x86的SSE),而且还可以更好地使用为OpenGL设计的其他库(出于同样的原因使用列主矩阵)。您只需与存储保持一致,不要在不同的函数调用中混淆它。

只需查找OpenGL规范。每个操作都有所有矩阵公式。谢谢Erik。这里的含义是,您正在批量处理所有平移、缩放和旋转更改,并在之前将它们作为一个矩阵构建e渲染。如果我一次只在“当前矩阵”中进行一次渲染,我会试图找出其行为。如果我的问题不合理,那么请帮助我理解?谢谢。你说的“批处理”到底是什么意思?即使使用预opengles 2矩阵堆栈,你也必须调用glPushMatrix()和glPopMatrix()在某些情况下,如果你想转换多个对象。就我个人而言,我不明白你为什么要复制以前的堆栈行为…跟踪当前矩阵的外观是如此困难。尽管如此,没有什么可以阻止你将堆栈矩阵与glm一起使用。感谢你的进一步了解和更新。我想说的是真正要问的是,如果我的操作是:平移,旋转,平移,按顺序,这会执行一些不同于预先知道我所有旋转和平移的操作序列。这不是保持一个很难的堆栈,而是理解我如何获得平移,然后旋转,然后从我的乘法器中平移行为这有帮助吗?我不确定你的意思,但没有区别;只需将矩阵(正如Christian在他的回答中提到的)右乘,结果应该是正确的。我只需要分两步来做:m'=t1M x rM;m'=t2M x m';谢谢。你能解释一下你使用的符号吗(我不知道t1-、t2-和r-前缀是什么意思)为什么要分两步来做?