OpenGL中的缩放旋转与平移
# OpenGL中的缩放旋转与平移
本章需要熟知线性代数中的旋转矩阵的知识。
# 坐标系的旋转(Rotate)
对于一个绝对矢量,在坐标系1下的坐标为,在坐标系2下的坐标为,已知坐标系1到坐标系2的旋转矩阵为,则有关系式:
该公式表示的是绝对矢量在不同坐标系下的坐标变换关系。
# 坐标系的平移(Translate)
通常采用扩维的方法表示坐标系的平移。对于旋转矩阵如下:
如果在与分量平移和,则有附加平移的旋转矩阵:
此时原坐标需要扩为。
glm::mat4 glm::translate(glm::vec3 translation);
绝对矢量不随坐标系移动,因而平移项起作用,此时w=1
相对矢量无所谓平移,此时w=0。因此可以通过设置w的值来表示是否有平移。
auto world_pos = glm::vec3(l2w*glm::vec4(local_pos,1)); auto world_vel = glm::vec3(l2w*glm::vec4(local_vel,0));
# 坐标的缩放(Scale)
利用矩阵中对角元素对各个分量进行缩放。
glm::mat4 glm::scale(glm::vec3 scales);
# 轴角法:实现绕任意轴旋转
轴角法即给定一根轴线和绕这个轴的旋转角度,求旋转矩阵。它实际上是罗德里格斯旋转公式(Rodrigues' Rotation Formula) (opens new window),其形式如下:
在glm中可以通过函数实现轴角法的旋转:
glm::mat4 glm::rotate(float rad, glm::vec3 axis);
# SRT(缩放、旋转、平移)顺序
一般缩放必须先于旋转,旋转必须先于平移,因此应用顺序必须为:缩放、旋转、平移。SRT
glm::mat4 l2w =
glm::translate(glm::vec3(0.0f,0.5f,0.0f))
* glm::rotate(glm::radians(45.0f),glm::vec3(0.0f,0.0f,1.0f))
* glm::scale(glm::vec3(2.0f,1.0f,1.0f));
# OpenGL中不同的空间以及转换矩阵
# 对象空间到世界空间(Local to World)[M]
对象空间中,模型本身为坐标原点;世界空间以世界中心为原点。
正如茶杯在对象空间原点,在桌子(世界空间)的左上角一样。
# 世界空间到视角空间(World to View)[V]
视角空间以观察点为原点。
正如我从桌子正前方观察桌子和茶杯。
# 视角空间到剪裁空间(View to Clip)[P]
经过投影矩阵的变换(经此变换,从右手系变为了左手系),让看的物体更加真实,符合透视规则。然后将屏幕以外的东西剔除剪裁。
为防止剪裁后屏幕非正方形而将物体压扁,需要在投影矩阵中“预判一下”,提前利用宽高比进行压缩。
# NDC to Window
剪裁空间经过光栅化到窗口空间。此时将-1~1的浮点数坐标,转换为0~1920或1080的像素坐标系。
# 投影变换的实现
为了符合透视原理,也就是“近大远小”,为了让计算机能够渲染出这样的效果,我们需要一个定量的公式。假设为物体距离眼睛的距离,从眼睛看向屏幕,前方为z正值,此时可以根据距离大小,将物体缩小倍,即:
由于非线性,不容易用矩阵表示。
升维大法!!:利用矩阵变换将分量搬运到分量,然后规定从4维转回到3维矢量时,要额外除以他们的分量,这样就可以实现,过程如下:
当降维时,所有分量除以,则有:
代码实现:
// 对于绝对矢量
glm::vec4 tmp4d_pos = v2c * glm::vec4(pos,1);
glm::vec3 new_pos = glm::vec3(
tmp4d_pos.x / tmp4d_pos.w,
tmp4d_pos.y / tmp4d_pos.w,
tmp4d_pos.z / tmp4d_pos.w
);