1.使用OpenGL Mathematics,下载GLM后,将文件路径加入包含路径(不需要编译和链接)
2.平移、旋转、缩放矩阵
glm::vec4 vec(1.0f,0.0f,0.0f,1.0f);
//默认是一个单位矩阵(9.9版本之后的GLM应改为glm::mat4 trans(1.0f);)
glm::mat4 trans;
//缩放
trans = glm::scale(trans,glm::vec3(0.5,0.5,0.5));
//旋转
trans = glm::rotate(trans,glm::radians(90.0f),glm::vec3(0.0,0.0,1.0));
//平移
trans = glm::translate(trans,glm::vec3(1.0f,1.0f,0.0f));
vec = trans*vec;
3.注意:代码的书写顺序不等于实际变换顺序
因为:shader中顶点坐标是vec4变量,相当于四行一列矩阵,所以gl_position = mvpMatrix * vec4(vertexCoord);代码中最后进行的变换最先与顶点坐标进行相乘,即:
代码中变换顺序是glm:scale,glm:rotate,glm:translate,shader中的实际顺序是:matrix_scale * matrix_rotate * matrix_translate * vec4(vertexCoord),矩阵乘法满足结合律,
相当于matrix_scale * (matrix_rotate * (matrix_translate * vec4(vertexCoord))),所以代码书写顺序与实际变换顺序相反
4.视图矩阵,定义相机的位置,观察方向,相机右方向(x轴正方向),相机上方向
(1)相机位置
glm::vec3 cameraPos = glm::vec3(0.0f,0.0f,3.0f);
(2)摄像机方向(为了后面计算方便,我们使用摄像机方向的反向量,因为它指向z轴正方向)
glm::vec3 cameTarget = glm::vec3(0.0f,0.0f,0.0f);
glm::cameraDirection = glm::normalize(cameraPos - cameraTarget);
(3)右轴:首先定义一个不与摄像机方向平行的向量,进行叉乘得到一个垂直于摄像机方向的向量,(为了方便,我们直接定义一个上向量,这样叉乘的结果就是x轴方向)
glm::vec3 up = glm::vec3(0.0f,1.0f,0.0f);
glm::vec3 cameraRight = glm::normalize(glm::cross(up,cameraDirection));
(4)上轴:将x和z轴叉乘得到y轴
glm::vec3 cameraUp = glm::cross(cameraDirection,cameraRight);
(5)lookat矩阵,由三个相互垂直的向量和一个位移向量可方便的将向量变换到该坐标空间
其中R是右向量,U是上向量,D是方向向量,P是摄像机位置(注意方向向量是实际上摄像机方向的相反值,因为相机的)glm提供了设置视图矩阵的方法:
glm::mat4 view;
view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f),glm::vec3(0.0f, 0.0f, 0.0f),glm::vec3(0.0f, 1.0f, 0.0f));
其中三个参数分别表示:摄像机位置、目标方向和上向量
关于设置视图矩阵的小技巧:
(1)保持方向不变:glm::lookAt( cameraPos , cameraPos + cameraFront , cameraUp),输入操作改变cameraPos,改变的大小值乘以cameraFront
(2)降低硬件渲染效率对移动速度的影响:设置相机移动速度是cameraSpeed,使用全局变量保存上一帧与当前帧渲染的时间差,当前帧的移动速度是cameraSpeed * deltaTime(时间差)
5.投影矩阵,定义可视空间(裁剪范围)
正射投影:
glm::ortho(0.0f, 800.0f, 0.0f, 600.0f, 0.1f, 100.0f);
四个参数依次是:可视空间的左平面坐标,右平面坐标,上平面,下平面,近平面和远平面
透视投影:
glm::mat4 proj = glm::perspective(glm::radians(45.0f), (float)width/(float)height, 0.1f, 100.0f);
四个参数依次是:仰角,宽高比,近平面,远平面
透视投影是通过改变齐次坐标的w分量来进行实现的,顶点着色器处理完后的顶点坐标输出是NDC坐标,坐标值被转化到[-1,1]区间是通过前三个分量处以w来实现的,距离相机越远w分量越大,所以远处的顶点坐标越小,最终两条平行直线会相交
6.启用深度缓冲
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);