将转换应用于对象

时间:2013-11-02 10:17:03

标签: opengl matrix transformation

我正在创建基本的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();

2 个答案:

答案 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);

将其发送为制服,并将其应用于对象的模型矩阵之后。 (我用它来渲染海洋反射到纹理。)

总结一下:

  • 创建全局视图(相机)矩阵
  • 为每个场景,网格或物体创建模型矩阵
  • 单独转换对象的矩阵
  • 通过制服将投影,模型和视图矩阵发送到着色器
  • 计算最终位置:proj * camera * model * vertex
  • 移动物体,移动相机

我并不是说没有更好的方法可以做到这一点,但这对我很有用。

PS:如果你想要一些相机类的东西,我有一个非常好的;)。