我已经在制作一个游戏引擎了。一开始我只用SDL实现了2D图形,但是现在我正在逐渐转向使用OpenGL实现3D功能。我看到的大部分有关“如何完成任务”的文档都使用GLUT,而我不使用GLUT。
问题是,我该如何在OpenGL中创建一个“相机”,以便我可以在3D环境中移动并正确地显示3D模型和精灵(例如,具有固定位置和旋转的精灵)?为了设置OpenGL相机,我需要关注哪些函数?这些函数应该按照什么顺序调用?
以下是一些背景信息,解释为什么我需要一个实际的相机。
要绘制一个简单的精灵,我从SDL表面创建一个GL纹理,并将其绘制到屏幕上的坐标为(SpriteX-CameraX)和(SpriteY-CameraY)的位置。这很好用,但是当我开始处理实际的3D模型时,就不太对了。相机的位置是一个自定义的向量类(即不使用标准库),带有X、Y、Z整数组件。
我有一个由三角形构成的3D立方体,单独拿出来,我可以绘制它并旋转它,我实际上可以通过在绘制模型时传入相机位置并使用该位置向量的组件来计算模型的位置来移动立方体(虽然有些别扭)。但是当我尝试旋转模型时,问题就显现出来了。模型的原点不是模型本身,而似乎是屏幕的原点。一些搜索告诉我,我需要保存模型的位置,围绕原点旋转它,然后将模型恢复到其原始位置。
与其通过计算新顶点来计算视口中应该绘制哪些东西,我想创建一个OpenGL“相机”来自动执行此任务,这样我只需要将我的Camera对象的坐标传递给OpenGL相机即可自动翻译视图。如果你使用GLUT,这个任务似乎非常容易,但是我不确定如何仅使用OpenGL设置相机。
编辑 #1(根据一些评论): 以下是我程序中调用的更新方法。它已经更新为创建透视和视图矩阵。所有绘制都在这个方法被调用之前完成。当OpenGL执行时,会执行类似的一组方法(减去缓冲区交换)。x、y、z坐标直接是相机实例及其位置向量。如果相机位于(256, 32, 0),则会将256、32和0传递给Update方法。目前,z被设置为0,因为目前没有办法更改该值。正在绘制的3D模型是一组顶点/三角形+法线,位于X=320,Y=240,Z=-128。当程序运行时,在填充模式下绘制它,然后在线框模式下绘制它,然后在稍微向右移动相机时,在移动后的填充模式下绘制另一个。看起来法线可能是问题的原因,但我认为更多的是我漏掉了一些非常重要的东西,或者没有完全理解glFrustum的NEAR和FAR参数实际上是做什么的。在我实现这些更改之前,我使用的是glOrtho,立方体渲染正确。现在如果我切换回glOrtho,一个面会渲染(绿色),旋转也很奇怪——可能是由于平移造成的。这个立方体有6种不同的颜色,每个面都有一个。红色、蓝色、绿色、青色、白色和紫色。
int VideoWindow::Update(double x, double y, double z)
{
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glFrustum(0.0f, GetWidth(), GetHeight(), 0.0f, 32.0f, 192.0f);
glMatrixMode( GL_MODELVIEW );
SDL_GL_SwapBuffers();
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glRotatef(0, 1.0f, 0.0f, 0.0f);
glRotatef(0, 0.0f, 1.0f, 0.0f);
glRotatef(0, 0.0f, 0.0f, 1.0f);
glTranslated(-x, -y, 0);
return 0;
}
最终编辑: 问题实际上是由于glFrustum函数的近和远参数以及glTranslated函数的Z值引起的。虽然改变这些值已经解决了问题,但我可能需要进一步了解这两个函数之间的关系。