我目前正在重构我的OpenGL程序(曾经是一个巨大的文件)来使用C ++类。基本框架如下所示:
我有一个带有Drawable
函数的接口virtual void Render(GLenum type) const = 0;
和一堆实现此接口的类(Sphere
,Cube
,Grid
,{{1 }},Plane
和PLYMesh
)。
在我的OBJMesh
我设置一个包含多个这些对象的场景,每个对象都有自己的着色器程序。在设置统一缓冲对象和每个程序的单个制服后,我正在呼叫main.cpp
。
在我的每个帧的glutMainLoop()
函数中,我要做的第一件事就是设置所有的转换矩阵,最后为场景中的每个对象调用上面提到的Display
函数:
Render
我现在的问题如下:使用当前代码,我为每个对象使用相同的void Display()
{
// Clear framebuffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
modelViewMatrix = glm::mat4(1.0);
projectionMatrix = glm::mat4(1.0);
normalMatrix = glm::mat4(1.0);
modelViewMatrix = glm::lookAt(glm::vec3(0.0, 0.0, mouse_translate_z), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
modelViewMatrix = glm::rotate(modelViewMatrix, -mouse_rotate_x, glm::vec3(1.0f, 0.0f, 0.0f));
modelViewMatrix = glm::rotate(modelViewMatrix, -mouse_rotate_y, glm::vec3(0.0f, 1.0f, 0.0f));
projectionMatrix = glm::perspective(45.0f, (GLfloat)WINDOW_WIDTH / (GLfloat)WINDOW_HEIGHT, 1.0f, 10000.f);
// No non-uniform scaling (only use mat3(normalMatrix in shader))
normalMatrix = modelViewMatrix;
glBindBuffer(GL_UNIFORM_BUFFER, ubo_global_matrices);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(modelViewMatrix));
glBufferSubData(GL_UNIFORM_BUFFER, 1 * sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(projectionMatrix));
glBufferSubData(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(normalMatrix));
glBindBuffer(GL_UNIFORM_BUFFER, 0);
// ************************************************** //
// **************** DRAWING COMMANDS **************** //
// ************************************************** //
// Grid
if (grid->GetIsRendered())
{
program_GRID_NxN->Use();
grid->Render(GL_LINES);
program_GRID_NxN->UnUse();
}
// Plane
...
// Sphere
...
// Swap front and back buffer and redraw scene
glutSwapBuffers();
glutPostRedisplay();
}
矩阵。如果我只想翻译球体,或只旋转平面而不改变顶点位置怎么办?在大型OpenGL程序中存储模型矩阵的最佳位置在哪里?将受保护的成员变量ModelView
放入glam::mat4 modelMatrix
接口怎么样?此外,是否应拆分模型和视图矩阵(例如,使用仅包含视图矩阵的Drawable
类)?
答案 0 :(得分:4)
我的回答主要基于Tom Dalling's excellent tutorial,但有一些细微的变化。
首先,所有视图和投影矩阵操作都应该在Camera类中。通过调用matrix()
方法,相机将提供获取视图和投影矩阵的便捷方式。
glm::mat4 Camera::matrix() const {
return projection() * view();
}
<强> Camera.cpp 强>
然后,对于此示例,您将拥有模型资产,其中包含渲染几何图形所需的所有内容。此资产应该是唯一的,并存储在 ResourceManager 或类似的东西中。
struct ModelAsset {
Shader* shader;
Texture* texture;
GLuint vbo;
GLuint vao;
GLenum drawType;
GLint drawStart;
GLint drawCount;
};
然后你有一个模型实例,它有一个指向assest的指针加上一个唯一的转换矩阵。通过这种方式,您可以创建具有自己唯一转换的特定资产的任意数量的实例。
struct ModelInstance {
ModelAsset* asset;
glm::mat4 transform;
};
ModelInstance cube;
cube.asset = &asset; // An asset that you created somewhere else (e.g. ResourceManager)
cube.transform = glm::mat4(); // Your unique transformation for this instance
要渲染一个实例,您将视图和模型矩阵作为制服传递给着色器,着色器完成其余的工作。
shaders->setUniform("camera", camera.matrix());
shaders->setUniform("model", cube.transform);
最后,最好将所有实例分组到一个可调整大小的容器中。
std::vector<ModelInstance> instances;
instances.push_back(cube);
instances.push_back(sphere);
instances.push_back(pyramid);
for (ModelInstance i : instances) {
i.transform = glm::rotate(i.transform, getTime(), glm::vec3(0.0f, 1.0f, 0.0f));
}