[图形学学习笔记]OpenGL视图矩阵变换
模型矩阵
这个三维模型,是由一组顶点定义的。顶点的XYZ坐标是相对于物体中心定义的:也就是说,若某顶点位于(0, 0, 0),它就在物体的中心。
也许玩家需要用键鼠控制这个模型,所以我们希望能够移动它。这简单,只需学会:缩放 旋转 平移就行了。在每一帧中,用算出的这个矩阵,去乘(在GLSL中乘,不是C++中!)所有的顶点,物体就动了。唯一不动的就是世界坐标系(World Space)的中心。
现在,物体所有顶点都位于世界坐标系。下图中黑色箭头的意思是:从模型坐标系(Model Space)(顶点都相对于模型的中心定义)变换到世界坐标系(顶点都相对于世界坐标系中心定义)。
视图矩阵
此图展示了:从世界坐标系(顶点都相对于世界坐标系中心定义)到观察坐标系(Camera Space,顶点都相对于相机定义)的变换。
GLM使用了glm::LookAt函数来计算这个变换矩阵:
glm::mat4 CameraMatrix = glm::LookAt(
cameraPosition, // the position of your camera, in world space
cameraTarget, // where you want to look at, in world space
upVector // probably glm::vec3(0,1,0), but (0,-1,0) would make you looking upside-down, which can be great too
);
视图变换矩阵推导
我们希望得到模型在观察坐标系上的坐标,只需要对模型的坐标进行矩阵变换,而这个矩阵其实就是观察坐标系变换为世界坐标系的矩阵。如glm::LookAt函数的参数所示,根据前两个参数我们可以得到一个向量a,即由相机望向目标的向量,而由第三个参数得到一个向量b,即相机的朝向。
如图中所示,根据a,b向量可以得到3个互相正交的单位向量,也就是一组正交基,这就是我们的观察坐标系。
如图的正交矩阵,与(Xu,Yu,Zu)相乘得到(1,0,0),与(Xv,Yv,Zv)相乘得到(0,1,0),与(Xw,Yw,Zw)相乘得到(0,0,1)。
所以我们可以将这个矩阵当做是由uvw坐标转换为xyz坐标的旋转矩阵
。但在做旋转之前我们首先需要将uvw坐标轴的原点由camera的位置移至xyz坐标轴的原点。
因此需要先左乘一个平移矩阵,再乘旋转矩阵,如图,我们得到了坐标轴变换矩阵,也即glm::LookAt函数中的变换矩阵。
旋转矩阵补充
在三维旋转理论体系中,罗德里格旋转公式(根据欧林·罗德里格命名)是在给定转轴和旋转角度后,旋转一个向量的有效算法。如果v是在{R}^3中的向量,k是转轴的单位向量,θ是旋转角度(根据叉乘的方向确定正负号),那罗德里格旋转公式表达为:
矩阵形式:
示例代码:
mat3 Transform::rotate(const float theta, const vec3& axis) {
auto axis1 = glm::normalize(axis);
auto x = axis1[0],y=axis1[1],z=axis1[2];
mat3 mtx1(1,0,0,0,1,0,0,0,1);
mat3 mtx2(x x,x y,x z,x y,y y,y z,x z,y z,z
z);
mat3 mtx3(0,z,-y,-z,0,x,y,-x,0);
mtx1 +(1-cos(theta)) mtx2+sin(theta) mtx3;
return mt;
}
模型矩阵
这个三维模型,是由一组顶点定义的。顶点的XYZ坐标是相对于物体中心定义的:也就是说,若某顶点位于(0, 0, 0),它就在物体的中心。
也许玩家需要用键鼠控制这个模型,所以我们希望能够移动它。这简单,只需学会:缩放 旋转 平移就行了。在每一帧中,用算出的这个矩阵,去乘(在GLSL中乘,不是C++中!)所有的顶点,物体就动了。唯一不动的就是世界坐标系(World Space)的中心。
现在,物体所有顶点都位于世界坐标系。下图中黑色箭头的意思是:从模型坐标系(Model Space)(顶点都相对于模型的中心定义)变换到世界坐标系(顶点都相对于世界坐标系中心定义)。
视图矩阵
此图展示了:从世界坐标系(顶点都相对于世界坐标系中心定义)到观察坐标系(Camera Space,顶点都相对于相机定义)的变换。
GLM使用了glm::LookAt函数来计算这个变换矩阵:
glm::mat4 CameraMatrix = glm::LookAt(
cameraPosition, // the position of your camera, in world space
cameraTarget, // where you want to look at, in world space
upVector // probably glm::vec3(0,1,0), but (0,-1,0) would make you looking upside-down, which can be great too
);
视图变换矩阵推导
我们希望得到模型在观察坐标系上的坐标,只需要对模型的坐标进行矩阵变换,而这个矩阵其实就是观察坐标系变换为世界坐标系的矩阵。如glm::LookAt函数的参数所示,根据前两个参数我们可以得到一个向量a,即由相机望向目标的向量,而由第三个参数得到一个向量b,即相机的朝向。
如图中所示,根据a,b向量可以得到3个互相正交的单位向量,也就是一组正交基,这就是我们的观察坐标系。
如图的正交矩阵,与(Xu,Yu,Zu)相乘得到(1,0,0),与(Xv,Yv,Zv)相乘得到(0,1,0),与(Xw,Yw,Zw)相乘得到(0,0,1)。
所以我们可以将这个矩阵当做是由uvw坐标转换为xyz坐标的旋转矩阵
。但在做旋转之前我们首先需要将uvw坐标轴的原点由camera的位置移至xyz坐标轴的原点。
因此需要先左乘一个平移矩阵,再乘旋转矩阵,如图,我们得到了坐标轴变换矩阵,也即glm::LookAt函数中的变换矩阵。
旋转矩阵补充
在三维旋转理论体系中,罗德里格旋转公式(根据欧林·罗德里格命名)是在给定转轴和旋转角度后,旋转一个向量的有效算法。如果v是在{R}^3中的向量,k是转轴的单位向量,θ是旋转角度(根据叉乘的方向确定正负号),那罗德里格旋转公式表达为:
矩阵形式:
示例代码:
mat3 Transform::rotate(const float theta, const vec3& axis) {
auto axis1 = glm::normalize(axis);
auto x = axis1[0],y=axis1[1],z=axis1[2];
mat3 mtx1(1,0,0,0,1,0,0,0,1);
mat3 mtx2(x x,x y,x z,x y,y y,y z,x z,y z,z
z);
mat3 mtx3(0,z,-y,-z,0,x,y,-x,0);
mtx1 +(1-cos(theta)) mtx2+sin(theta) mtx3;
return mt;
}