OpenGL第一人称相机旋转和平移
OpenGL first person camera rotation and translation
我正在尝试编写一个简单的迷宫游戏,而不使用任何不推荐使用的OpenGL API(即没有即时模式)。我为迷宫中的每个瓦片使用一个顶点缓冲对象,它本质上是四个Vertex
的组合:
class Vertex {
public:
GLfloat x, y, z; // coords
GLfloat tx, ty; // texture coords
Vertex();
};
并存储在VBO中,如下所示:
void initVBO()
{
Vertex vertices[4];
vertices[0].x = -0.5;
vertices[0].y = -0.5;
vertices[0].z = 0.0;
vertices[0].tx = 0.0;
vertices[0].ty = 1.0;
vertices[1].x = -0.5;
vertices[1].y = 0.5;
vertices[1].z = 0.0;
vertices[1].tx = 0.0;
vertices[1].ty = 0.0;
vertices[2].x = 0.5;
vertices[2].y = 0.5;
vertices[2].z = 0.0;
vertices[2].tx = 1.0;
vertices[2].ty = 0.0;
vertices[3].x = 0.5;
vertices[3].y = -0.5;
vertices[3].z = 0.0;
vertices[3].tx = 1.0;
vertices[3].ty = 1.0;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*4, &vertices[0].x, GL_STATIC_DRAW);
ushort indices[4];
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
indices[3] = 3;
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ushort) * 4, indices, GL_STATIC_DRAW);
}
现在,我被摄像机的动作卡住了。在我项目的早期版本中,我使用glRotatef
和glTranslatef
平移和旋转场景,然后使用glBegin()
/glEnd()
模式渲染每个瓦片。但这两个函数现在已经不推荐使用了,而且我没有找到任何关于在仅使用VBO的上下文中创建相机的教程。哪种方法是正确的?我应该在每个瓦片之间循环吗?根据新的相机位置修改顶点的位置?
但这两个函数现在已经不推荐使用了,而且我没有找到任何关于在仅使用VBO的上下文中创建相机的教程。
VBO与此无关。
即时模式和矩阵堆栈是两种不同的鞋子。VBO处理将几何数据获取到渲染器,矩阵堆栈处理在那里进行转换。只有几何数据会受到VBO的影响。
至于你的问题:你自己计算矩阵,并通过均匀将它们传递给着色器。同样重要的是要理解OpenGL的矩阵函数从未被GPU加速过(除了一台机器,SGI的Onyx),所以这甚至没有提供一些性能提升。实际上,使用OpenGL的矩阵堆栈对整体性能产生了负面影响,因为它执行了冗余操作,而这些操作也必须在程序中的其他地方进行。
要获得一个简单的矩阵数学库,请查看我的linmath.h
http://github.com/datenwolf/linmath.h
我将添加到datenwolf的答案中。我假设只有着色器管道对您可用。
要求
在OpenGL 4.0+OpenGL中,当它离开固定函数管道时,它不会为您做任何渲染。如果现在在不使用着色器的情况下渲染几何体,则使用的是不推荐使用的管道。在没有一些基本框架的情况下启动和运行将是困难的(并非不可能,但我建议使用基本框架)。首先,我建议使用GLUT(这将为您创建一个窗口,并对空闲函数和输入进行基本回调)、GLEW(用于设置渲染上下文)和gLTools(用于快速设置的矩阵堆栈、通用着色器和着色器管理器,以便您至少可以开始渲染)。
设置
我会在这里给出重要的部分,然后你可以把它们拼凑起来。在这一点上,我假设你已经正确设置了GLUT(搜索如何设置它),并且你能够向它注册更新循环并创建一个窗口(也就是说,每个帧都调用你选择的函数之一的循环[注意,这不可能是一个方法])。有关此方面的帮助,请参阅上面的链接。
- 首先,初始化glew(通过调用
glewInit()
) - 设置场景。这包括使用GLBatch类(来自glTools)创建一组要渲染为三角形的顶点,并通过调用其
InitializeStockShaders()
函数初始化GLShaderManager类别(也来自glTools)及其库存着色器 - 在空闲循环中,调用着色器管理器的
UseStockShader()
函数以启动新的批处理。对顶点批处理调用draw()
函数。有关glTools的完整概述,请访问此处 - 不要忘记在渲染前清除窗口,并通过分别调用
glClear()
和glSwapBuffers()
在渲染后交换缓冲区
请注意,我上面给出的大多数函数都接受参数。你应该能够通过查看各自图书馆的文档来弄清楚这些。
MVP矩阵(编辑:忘记添加此部分)
OpenGL从z轴向下渲染-1,1坐标中的所有内容。它没有相机的概念,也不关心这些坐标之外的任何东西。模型视图投影矩阵是将场景转换为适合这些坐标的矩阵。
作为一个起点,在屏幕上渲染了一些东西之前,不要担心这一点(确保给顶点批处理的所有坐标都小于1)。完成后,使用glTools中的GLFrustum
类设置投影矩阵(默认投影为正交投影)。您将从这个类中获得投影矩阵,并将其与模型视图矩阵相乘。模型视图矩阵是模型的变换矩阵和摄影机的变换的组合(请记住,没有摄影机,所以本质上是在移动场景)。将所有矩阵相乘形成一个矩阵后,使用UseStockShader()
函数将其传递给着色器。
在GLTools中使用库存着色器(例如GLT_SHADER_FLAT
),然后开始创建自己的着色器。
参考
最后,我强烈建议你读这本书:OpenGL SuperBible,综合教程和参考(第五版-确保是这个版本)
如果您真的想坚持使用最新的OpenGL API,其中删除了许多功能以支持可编程管道(OpenGL 4和OpenGL ES 2),则必须自己编写顶点和片段着色器,并在其中实现转换。您必须手动创建着色器中使用的所有属性,特别是示例中使用的坐标和纹理坐标。如果你想模仿旧的固定功能OpenGL的行为,你还需要两个统一的变量,一个用于模型视图矩阵,另一个用于投影矩阵。
你习惯做的旋转/平移是矩阵运算。在管道的顶点变换阶段(现在由您提供的顶点着色器执行),您必须将4x4变换矩阵乘以顶点位置(4个坐标,解释为4x1矩阵,如果您没有做任何太花哨的事情,其中第4个坐标通常为1)。根据该变换,得到的矢量将处于正确的相对位置。然后将投影矩阵乘以该向量,并将结果输出到片段着色器。
您可以通过查看glRotate
、glTranslate
和gluPerspective
的文档来了解所有这些矩阵是如何构建的。记住,矩阵乘法是非可换的,所以你把它们相乘的顺序很重要(这正是为什么你称之为glRotate
和glTranslate
也很重要)。
关于学习GLSL和如何使用着色器,我在这里学到了,但这些教程与OpenGL 1.4和2有关,现在已经很旧了。主要区别在于,顶点着色器的预定义输入变量(如gl_Vertex
和gl_ModelViewMatrix
)已不存在,您必须自己创建它们。
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 与互斥锁相比,旋转锁可以保证上下文切换
- 绘制旋转的三角形
- 获取向量C++中第一个值和最后一个值的和
- 旋转模型矩阵时的形状失真
- 四边形的 2D 旋转
- 基于Quaternion的第一人称视图相机
- 如何朝面向方向移动第一人称对象?(C )
- C++ 快板第一个显示程序 - 平移旋转刻度
- OpenGL第一人称摄像机不移动
- OpenGL-第一人称相机矩阵出现问题
- 3D第一人称摄像机以角度扫射
- 使用四元数方向的第一人称摄像机中的钳制间距
- 在第一人称视图和第三人称视图之间切换(OpenGL)
- OpenGL第一人称相机旋转和平移
- 第一人称相机,旋转OPENGL
- c++第一人称相机在directx
- 可扩展的第一人称射击在c++
- C++DirectX第一人称相机
- 如何使用std::rotate来旋转第一个成员为const的pair数组?