我正在创建基本的OpenGL场景,我遇到了使用我的对象进行操作的问题。每个都有不同的变换矩阵,还有整个场景的模型视图/平移/缩放矩阵。
如何在从顶点着色器执行计算之前绑定此数据tomy对象?我读过关于gl(Push | Pop)Matrix()的内容,但这些函数已经从我理解的内容中弃用了。
我的一些代码。顶点着色器的位置:
gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
C ++函数显示对象:
// Clear etc...
mat4 lookAt = glm::lookAt();
glLoadMatrixf(&lookAt[0][0]);
mat4 combined = lookAt * (mat4) sceneTranslation * (mat4) sceneScale;
glLoadMatrixf(&combined[0][0]);
mat4 objectTransform(1.0);
// Transformations...
// No idea if it works, but objects are affected by camera position but not individually scaled, moved etc.
GLuint gl_ModelViewMatrix = glGetUniformLocation(shaderprogram, "gl_ModelViewMatrix");
glUniformMatrix4fv(gl_ModelViewMatrix, 1, GL_FALSE, &objectTransform[0][0]);
// For example
glutSolidCube(1.0);
glutSwapBuffers();
答案 0 :(得分:5)
好吧,你不必使用glLoadMatrix和其他内置矩阵函数,因为它可能比处理你自己的矩阵更难。
一个简单的相机示例,没有控制它,它是一个静态相机:
glm::mat4x4 view_matrix = glm::lookAt(
cameraPosition,
cameraPosition+directionVector, //or the focus point the camera is pointing to
upVector);
它返回一个4x4矩阵,这是视图矩阵。
glm::mat4x4 projection_matrix =
glm::perspective(60.0f, float(screenWidth)/float(screenHeight), 1.0f, 1000.0f);
这是投影矩阵
现在你有了视图和投影矩阵,你可以将它发送到着色器:
gShader->bindShader();
gShader->sendUniform4x4("view_matrix",glm::value_ptr(view_matrix));
gShader->sendUniform4x4("projection_matrix",glm::value_ptr(projection_matrix));
绑定者是简单的glUseProgram(shaderprog);
统一程序是
void sendUniform4x4(const string& name, const float* matrix, bool transpose=false)
{
GLuint location = getUniformLocation(name);
glUniformMatrix4fv(location, 1, transpose, matrix);
}
您的模型矩阵对于每个对象都是独立的:
glm::mat4x4 model_matrix= glm::mat4(1); //this is the identity matrix, so its static
model_matrix= glm::rotate(model_matrix,
rotationdegree,
vec3(axis)); //same as opengl function.
这创建了一个模型矩阵,您也可以将它发送到着色器
gShader->bindShader();
gShader->sendUniform4x4("model_matrix",glm::value_ptr(model_matrix));
glm::value_ptr(...)
创建矩阵的二维数组。
不要使用glModelViewMatrix和gl_ProjectionMatrix, 矩阵通过制服发送。
uniform mat4 projection_matrix;
uniform mat4 view_matrix;
uniform mat4 model_matrix;
void main(){
gl_Position = projection_matrix*view_matrix*model_matrix*gl_Vertex;
//i wrote gl_Vertex because of the glutSolidTeapot.
}
我从来没有在网格函数中使用过这个版本,所以我不知道它是如何工作的,假设它是使用立即模式使用gl_Vertex将顶点发送到着色器。 如果您创建自己的网格,请使用VBO vertexattribpointer和drawarrays / elements。
在发送制服之前不要忘记绑定着色器。
所以有一个完整的例子:
glm::mat4x4 view_matrix = glm::lookAt(2,4,2,-1,-1,-1,0,1,0);
glm::mat4x4 projection_matrix =
glm::perspective(60.0f, float(screenWidth)/float(screenHeight), 1.0f, 10.0f);
glm::mat4x4 model_matrix= glm::mat4(1); //this remains unchanged
glm::mat4x4 teapot_model_matrix= glm::rotate(model_matrix, //this is the teapots model matrix, apply transformations to this
45,
glm::vec3(1,1,1));
teapot_model_matrix = glm::scale(teapot_model_matrix,vec3(2,2,2);
gShader->bindShader();
gShader->sendUniform4x4("model_matrix",glm::value_ptr(model_matrix));
gShader->sendUniform4x4("view_matrix",glm::value_ptr(view_matrix));
gShader->sendUniform4x4("projection_matrix",glm::value_ptr(projection_matrix));
glutSolidCube(0.0); //i don't know what the (0.0) stands for :/
glutSwapBuffers();
///////////////////////////////////
着色器中的:
uniform mat4 projection_matrix; //these are the matrixes you've sent
uniform mat4 view_matrix;
uniform mat4 model_matrix;
void main(){
gl_Position = projection_matrix*view_matrix*model_matrix*vec4(gl_Vertex.xyz,1);
}
现在你应该将相机定位在2,4,2,聚焦在-1,-1,-1,并且向上矢量指向上方:)
茶壶围绕(1,1,1)向量旋转45度,并在每个方向上按2缩放。
更改模型矩阵后,将其发送到着色器,如果有更多对象要渲染 如果要对每个网格应用不同的转换,请在每个之后发送它。 对此的伪代码如下:
camera.lookat(camerapostion,focuspoint,updirection); //sets the view
camera.project(fov,aspect ratio,near plane, far plane) //and projection matrix
camera.sendviewmatrixtoshader;
camera.sendprojectionmatrixtoshader;
obj1.rotate(45 degrees, 1,1,1); //these functions should transform the model matrix of the object. Make sure each one has its own.
obj1.sendmodelmatrixtoshader;
obj2.scale(2,1,1);
obj2.sendmodelmatrixtoshader;
如果不起作用,请尝试使用vertexBuffer,以及自己创建的简单三角形或立方体。
答案 1 :(得分:3)
你应该使用数学库,我推荐GLM。它具有与OpenGL类似的矩阵函数,并使用列主矩阵,因此您可以计算自己的所有权,并将它们应用于对象。
首先,您应该为场景设置矩阵类,以计算视图矩阵和投影矩阵。 (glm :: lookAt和glm :: project)。它们的工作方式与openGL相同。您可以将它们作为制服发送到顶点着色器。
对于obejcts,您可以计算自己的marix,并将它们作为模型矩阵发送到着色器。
在着色器或cpu中计算mv矩阵:
vp = proj*view.
您将各个模型矩阵发送到着色器并计算最终位置:
gl_Position = vp*m*vec4(vertex.xyz,1);
MODEL MATRIX
使用glm,您可以轻松计算,转换矩阵。您创建一个简单的单位矩阵:
glm::mat4x4(1) //identity
你可以翻译,旋转,缩放它。
glm::scale
glm::rotate
glm::translate
它们在opengl中以立即模式工作。
让你的矩阵通过制服发送。
MORE MODEL MATRIX
shader->senduniform("proj", camera.projectionmatrix);
shader->senduniform("view", camera.viewmatrix);
glm::mat4 model(1);
obj1.modelmatrix = glm::translate(model,vec3(1,2,1));
shader->senduniform("model", obj1.modelmatrix);
objectloader.render(obj1);
obj2.modelmatrix = glm::rotate(model,obj2.degrees,vec3(obj2.rotationaxis));
shader->senduniform("model", obj2.modelmatrix);
objectloader.render(obj2);
这只是一种方法。您可以为推/弹矩阵计算编写一个类,自动执行上面的方法,如下所示:
obj1.rotate(degrees,vec3(axis)); //this calculates the obj1.modelmatrix for example rotating the identity matrix.
obj1.translate(vec3(x,y,z))//more transform
obj1.render();
//continue with object 2
查看矩阵
视图矩阵与模型矩阵几乎相同。用它来控制全局“模型矩阵”,即相机。这会全局转换您的屏幕,您可以单独为对象设置模型矩阵。
在我的相机类中,我使用glm :: lookAt(与opengl相同)计算它,然后通过制服将其发送到我使用的所有着色器。
然后,当我渲染某些东西时,我可以操纵它的模型矩阵,旋转或缩放它,但视图矩阵是全局的。
如果你想要一个静态物体,你不必在它上面使用模型矩阵,你只需要计算位置:
gl_Position = projmatrix*viewmatrix*staticobjectvertex;
GLOBAL MODEL MATRIX
您也可以拥有全局模型矩阵。
像
一样使用它renderer.globmodel.rotate(axis,degree);
renderer.globmodel.scale(x,y,z);
将其发送为制服,并将其应用于对象的模型矩阵之后。 (我用它来渲染海洋反射到纹理。)
总结一下:
我并不是说没有更好的方法可以做到这一点,但这对我很有用。
PS:如果你想要一些相机类的东西,我有一个非常好的;)。