我正在将玩具GL ES 1.1代码库移植到GL ES 2.0。没有内置的模型视图矩阵操作,因此我尝试用4x4“当前矩阵”的操作来替换glScalef
,glTranslatef
,glRotatef
调用。< / p>
然而,我的矩阵数学有点粗略,并且正在进行乘法排序和行与列主要表示法等等,如果有人可以快速概述我应该放在这里的语义,我会喜欢它。
例如,假设我以身份矩阵开头,然后(在ES 1.1代码中)按顺序执行:
glTranslate(A);
glRotate(B);
glTranslate(C);
...我需要在我的“当前矩阵”上做什么数学运算才能在我发送到着色器的最终模型视图矩阵中复制此功能?我已经尝试保留一个矩阵,并为每个操作创建一个代表它的新矩阵,并将其乘以当前的矩阵。结果虽然不正确,但我觉得有些事情我没有得到关于前/后乘法, - 主要等等。
有人愿意在这里对这个理论说几句话吗?谢谢。 (我希望在提高效率之前先了解基础知识。)
(这:Implement the Fixed function Pipeline efficent in OpenGL ES 2.0? 问一个类似的问题,但答案是关于如何提高效率,并没有真正启发我的数学等价性。)
答案 0 :(得分:2)
基本上,您正在寻找替换opengl矩阵堆栈来进行转换。
假设您使用的是c / c ++,我建议您查看GLM库:http://glm.g-truc.net/
它是一个仅限标题的库,易于使用,是pre-opengl es 2.0矩阵堆栈的完美替代品。它甚至为不推荐使用的glu函数提供了功能,例如gluOrtho()和gluPerspective()。 Glm的矩阵很容易传递到着色器,因为它们是以着色器构思的。
您必须对代码进行一些更改;例如,将您自己的顶点/矩阵定义转换为glm :: vec3 / glm :: mat4。
这是我如何构建我传递给顶点着色器的mvp矩阵的示例:在这种情况下,actorInstance类有一些属性,如position(在世界中)和旋转定义为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()......
答案 1 :(得分:1)
我试过保留一个矩阵,并为每个操作创建一个新的 代表它的矩阵,并将其乘以当前的矩阵。
嗯,这就是它的完成方式。没什么好看的。
拨打glRotate
,glTranslate
和glScale
(以及glOrtho
,glFrustum
,gluLookAt
和{{3}的相应矩阵当然,这很容易构建,如链接中所示。
您只需要在当前矩阵T
上右对乘变换矩阵M
:
M' = M * T
因为我们(或者您要复制的旧OpenGL)希望在绘制之前调用的最后一个转换首先应用于对象。
然后,您还必须与矩阵的存储(行主要与列主要)保持一致,无论您解决哪个问题。但是由于你使用的是OpenGL,因此列主要存储是一个好主意,因为它让你更容易上传它们(不过没有反对transpose-flag),对于矢量化SIMD指令(比如x86的SSE)效果更好而且对于为OpenGL设计的其他库(出于同样的原因使用列主矩阵)更好地工作。您只需要与存储保持一致,不要在不同的函数调用中混淆它。