2012-02-06 37 views
1

我将一个玩具GL ES 1.1代码库移植到GL ES 2.0中。有没有内置的模型视图矩阵运算,所以我试图在更换glScalefglTranslatefglRotatef电话与一个4x4“当前矩阵”操作的下降。手动复制GL矩阵运算的序列

但是,我的矩阵数学有点粗略,并且正在进行乘法排序和行vs列主要记法等,如果有人能够快速勾画出我应该放在这里的语义,我会很喜欢它。

例如,假设我开始与单位矩阵,然后(在ES 1.1的代码)执行顺序为:

glTranslate(A); 
glRotate(B); 
glTranslate(C); 

...我需要对我的“当前矩阵在做什么数学“在我发送给着色器的最终模型视图矩阵中复制这个功能?我试着保留一个矩阵,并为每个操作,创建一个代表它的新矩阵,并将它乘以当前矩阵。其结果是不正确的,虽然,我觉得有件事情我没有得到有关前/后乘, - 主要等等

任何人都愿意说就在这里的理论几句话?谢谢。 (我想在使它超级高效之前了解基础知识)。

(This:Implement the Fixed function Pipeline efficent in OpenGL ES 2.0? 问一个类似的问题,但答案是谈论如何使它更有效率,而且并没有真正启发我在数学等价。)

+0

刚刚查找OpenGL规范。每个操作都有矩阵公式。 – alxx 2012-02-06 08:25:25

回答

2

基本上,你正在寻找一个替代OpenGL的矩阵堆栈的做你的转换。

假设你正在使用C/C++,我建议有一个看GLM库:http://glm.g-truc.net/

这是一个只有头库,易于使用,并为预OpenGL ES 2.0的矩阵堆栈的完美替代。它甚至为gluOrtho()和gluPerspective()等不推荐的glu函数提供了功能。 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从我的相机类传下来。 这个矩阵然后被用来渲染网格:

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 

,这是你glLoadIdentity( )...

+0

谢谢埃里克。这里的含义是,你正在加紧处理所有的翻译,缩放和旋转变化,并在渲染之前将它们全部作为一个矩阵构建。我试图弄清楚如果我一次一个地将它们放入“当前矩阵”中的行为。如果我的问题不明智,那么请帮助我理解?谢谢。 – 2012-02-06 15:21:23

+1

你是什么意思的“配合”?即使使用预操作2矩阵堆栈,如果要转换多个对象,也必须在某处调用glPushMatrix()和glPopMatrix()。就个人而言,我不明白你为什么要复制以前的堆栈行为......跟踪当前矩阵的外观是如此困难。话虽如此,没有什么能阻止你使用glm堆叠矩阵。 – Erik 2012-02-06 15:33:39

+0

查看我编辑的答案 – Erik 2012-02-06 15:45:42

1

我试着保留一个矩阵,并为每个操作,使一个新的代表它的 矩阵,并将其乘以当前的矩阵。

嗯,就是这样做。没有什么奇特的。

将呼叫glRotateglTranslateglScale(和也glOrthoglFrustumgluLookAtgluPerspective,当然)的各矩阵是相当容易构造,如在链接看到。

你只需要右键乘以相应的变换矩阵T在当前矩阵M

M' = M * T 

,因为我们(或者要复制旧的OpenGL)要绘制之前被调用最后转换首先应用于对象。

然后,您还必须与您矩阵的存储(行 - 主 - 列 - 专业)保持一致,无论您解决哪个问题。但是由于你使用的是OpenGL,所以列专业存储将是一个好主意,因为它让你可以更容易地将它们上传到GLSL(尽管对转置标志没有任何反应),但对于矢量化SIMD指令(如x86的SSE)而且与其他为OpenGL设计的库(使用列主矩阵出于同样的原因)效果更好。你只需要与存储保持一致,不要在不同的函数调用中混淆。