1、画立方体
- 之前我们绘制的都是二维图形,今天开始我们将进入三维图形的绘制,三维图形是在二维(XY轴)平面基础上,增加了深度(Z轴),所以三维图形更具有空间感。
- 二维变三维,图形的顶点个数会增加很多,之前的一个二维平面只需要使用4个顶点就可以描述,由于图形学的基本图元是三角形,一个长方形可分割成两个三角形,一共使用6个顶点即可表示
- 三维图形由于新增了一个维度,一个立方体一共有8个顶点,6个平面,每个平面由两个三角形组成,一共就是12个三角形,每个三角形由3个顶点确定,所以一共需要用到36个顶点
- 下图为长度为2的立方体,原点位于立方体中心,8个顶点坐标如下所示,顶点坐标在程序中会通过顶点缓冲区VBO传递给顶点着色器
2、模型矩阵,视图矩阵和投影矩阵
三维世界的观察者
- 要让观察者看到三维场景,也就是在计算机中要将三维场景绘制到二维的平面上,在现实中,屏幕相当于代替了我们的眼睛
- 想象屏幕是一个摄像头,这个摄像头看到的景象就是最终呈现在屏幕上的效果,也可以理解这个摄像头是一个观察者。
- 定义一个观察者的状态,主要有三个要素:
- 视点,也就是观察者的位置
- 观察目标点,即被观察目标所在的点,视点和目标点一起可以确定视线
- 还有最后一个上方向,因为我们最后要把观察到的景象绘制到屏幕上
视图矩阵:
- glm库中描述观察者状态(视点坐标,目标点坐标,上方向),有一个专门的描述函数 glm::lookAt
- vec3变量eye,指定观察者坐标位置
- vec3变量center,指定目标点点位置,与eye共同确定视线方向,一般使用原点作为
- vec3变量up,用于指定屏幕的上方向,一般采用Y轴正方向作为上方向。(glm::vec3(0.0f, 1.0f, 0.0f))
glm::mat4 viewMatrix glm::lookAt(const vec<3, T, Q> &eye,
const vec<3, T, Q> ¢er,
const vec<3, T, Q> &up);
投影矩阵:
- 投影矩阵用于确定可视空间范围,也就是观察者能够看到的区域大小,投影矩阵一共有两种,正射投影和透视投影
正射投影: 也称盒状空间,他的可视空间由前后两个矩形表面确定,这两个表面也被称为近裁剪面和远裁剪面,只有在此空间内的物体才会被显示出来
- opengl中提供ortho方法用于定义正射投影矩阵,其中left,right,bottom,top表示截面的的范围,near和far分别表示观察点距离近裁剪面和远裁剪面的距离。
glm::ortho(T left, T right, T bottom, T top, T zNear, T zFar);
- 示意图
透视投影 :模拟人眼看物体的透视效果,可以实现远处的东西看上去更小的效果,可以更好的体现深度感
- 透视投影矩阵通过perspective方法制定,其中参数fovy表示视角范围,即可视空间顶面和底面间的夹角,数值大于0,aspect用于指定近裁剪面的宽高比。near,far分别表示视点距离近裁剪面和远裁剪面的距离。
glm::perspective(T fovy, T aspect, T zNear, T zFar);
模型矩阵:
- 模型矩阵一般用于指定顶点坐标的变换,包括偏移,旋转和缩放
- OpenGL程序通过使用投影矩阵定义可视空间,使用视图矩阵定义观察者状态,才通过模型矩阵对顶点进行矩阵变化操作,最后计算得到顶点的位置
3、实战-绘制立方体
着色器代码GLSL
const char *vertex_shader =
"#version 410 \n"
"layout(location=0) in vec3 a_Position; \n"
"uniform mat4 u_ModelMatirx; \n" // 模型矩阵
"uniform mat4 u_ViewMatirx; \n" // 视图矩阵
"uniform mat4 u_ProjMatirx; \n" // 投影矩阵
" void main() {"
" gl_Position = u_ProjMatirx * u_ViewMatirx * u_ModelMatirx * vec4(a_Position, 1.0); \n"
"}";
通过VBO传递顶点坐标数据,一共有36个顶点数据
void init(GLFWwindow* window) {
// 36个顶点
float vPositions[108] = {
-1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f,
1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f,
1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f
};
// 创建vao,并绑定
glGenVertexArrays(1, vao);
glBindVertexArray(vao[0]);
// 创建顶点缓冲对象vbo
glGenBuffers(2,vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
// 将数据填充到缓冲区对象中
glBufferData(GL_ARRAY_BUFFER,sizeof(vPositions),vPositions,GL_STATIC_DRAW);
}
分别为模型矩阵、视图矩阵和投影矩阵设置值
GLuint u_ModelMatirx = glGetUniformLocation(renderProgram,"u_ModelMatirx");
GLuint u_ViewMatirx = glGetUniformLocation(renderProgram,"u_ViewMatirx");
GLuint u_ProjMatirx = glGetUniformLocation(renderProgram,"u_ProjMatirx");
// 模型矩阵,对立方体,沿Y轴旋转30度,并向Y轴负方向偏移2个单位
glm::mat4 rotate = glm::rotate(glm::mat4(1.0f),glm::radians(30.0f),
glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 trans = glm::translate(glm::mat4(1.0f),glm::vec3(0.0f, -2.0f, 0.0f));
glm::mat4 modelMatrix = trans * rotate;
glUniformMatrix4fv(u_ModelMatirx, 1, GL_FALSE, glm::value_ptr(modelMatrix));
// 视图矩阵
// 视点位置为(0.0f, 0.0f, 8.0f),以原点作为目标点,Y轴正方向为上方向
glm::mat4 viewMatrix = glm::lookAt(glm::vec3(0.0f, 0.0f, 8.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f));
glUniformMatrix4fv(u_ViewMatirx, 1, GL_FALSE, glm::value_ptr(viewMatrix));
// 透视投影
// 可视范围为60度,近截面宽高比为1
glm::mat4 projMatrix = glm::perspective(glm::radians(60.0f), 1.0f, 0.1f, 100.0f );
glUniformMatrix4fv(u_ProjMatirx, 1, GL_FALSE, glm::value_ptr(projMatrix));
- 效果图
完整代码仓库
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END