【OpenGL】10-摄像机

参考教程

【中文版】摄像机

【英文版】Camera

学习心得

  在开始这一篇之前,我们需要清楚OpenGL中的坐标系规则,OpenGL采用右手坐标系,即伸出右手,让大拇指指向右方,食指向上,剩下手指弯曲90度指向自己,这即是X,Y,Z三轴。

right_hand

  关于右手坐标系的具体情况可以参考:左右手坐标系

  在我们之前的代码中,有这么一段:

1
2
3
4
5
glm::mat4 View = glm::lookAt(
glm::vec3(0, 0, 5),
glm::vec3(0, 0, 0),
glm::vec3(0, 1, 0)
);

  在这段中我们调用了 glm::lookAt 方法,并给其传入了三个vec3作为参数,那么这个方法到底是怎么操作的呢,首先看看这个方法的介绍:

1
2
3
4
5
detail::tmat4x4<T> glm::gtc::matrix_transform::lookAt	(	
detail::tvec3< T > const & eye,
detail::tvec3< T > const & center,
detail::tvec3< T > const & up
)

Build a look at view matrix.

  这个方法用来构建一个view矩阵,而我们需要给出的三个vec3分别是摄像机的坐标,摄像机的目标坐标,以及一个Up向量,摄像机的位置坐标和摄像机的观察目标自然不用说,那么这个Up向量又是做什么的呢?

  我们需要一个摄像机区域的 Right 向量表示摄像机空间里的X轴正方向,这个X轴正方向我们可以通过摄像机观察的方向(即摄像机->观察点的方向)与一个正向上的向量来进行叉乘来获得。

  当我们提供了摄像机坐标,观察点坐标以及一个向上的向量之后, lookAt 方法将为我们创建一个看着给定的观察点的矩阵(glm省去了我们的计算)。

  对于想学到更多数学原理的读者,提示一下,在线性代数中这个处理叫做格拉姆—施密特正交化(Gram-Schmidt Process)。使用这些摄像机向量我们就可以创建一个LookAt矩阵了,它在创建摄像机的时候非常有用。

  现在我们已经大致清楚了摄像机的使用,那么之前我们使用Model进行平移旋转等变换,现在则使用View矩阵的修改实现正方体观察的变换。首先关于平移我们可以通过修改观察点实现,而旋转可以通过修改摄像机的坐标来实现。

  请记住摄像机的变换和模型的变换是相反的,正如汽车向右走,那么坐在车里的我们可以看到路两旁的树在向左走。

1
2
3
4
5
6
7
8
9
10
11
glm::mat4 Projection = glm::perspective(glm::radians(90.0f), 4.0f / 3.0f, 0.1f, 10.0f);
// Camera matrix
glm::mat4 View = glm::lookAt(
glm::vec3(0,0,5), // Camera is at (0,0,5), in World Space
glm::vec3(0,0,0), // and looks at the origin
glm::vec3(0,1,0) // Head is up (set to 0,1,0 to look upside-down)
);
// Model matrix : an identity matrix (model will be at the origin)
glm::mat4 Model = glm::mat4(1.0f);
// Our ModelViewProjection : multiplication of our 3 matrices
glm::mat4 MVP = Projection * View * Model; // Remember, matrix multiplication is the other way around

  首先看看我们之前的M,V,P三个矩阵的定义(在纹理那篇文章时候的代码),现在我们通过修改 LookAt 中的观察点位置来模拟正方体的移动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
float X = 0;
int direct = 0;
do{
if(X > 5.0f || X < -5.0f){
direct = !direct;
}
if(direct) X += 0.1f;
else X -= 0.1f;

...

glm::mat4 View = glm::lookAt(
glm::vec3(0,0,5),
glm::vec3(X,0,0),
glm::vec3(0,1,0)
);

...

}while(...)

  由上边的代码可以看到,我们修改了 LookAt 方法的观察点参数,并让其在 5.0f 到 -5.0f 间交替,使得正方体在可见区域内来回移动。

MD不支持视频,我上传了Youtube,点这里看效果

  接下来我们通过修改摄像机的位置使得摄像机绕着正方体运动,同时摄像机的观察点一直在圆心(0,0,0),这种情况下我们可以模拟看到正方体的转动(其实是摄像机在转,与移动同理)。

  首先计算绕X轴旋转的Z轴坐标,绕Y轴旋转的话那么需要计算X和Z轴的值,我们使用 glfwGetTime() 获得一个变值,然后在X坐标上对其进行 Cos 计算,在Z坐标上对其进行 Sin 计算(绕Y轴旋转,Y轴不变)。

1
2
3
4
5
glm::mat4 View       = glm::lookAt(
glm::vec3(5 * cos(glfwGetTime()),0,5 * sin(glfwGetTime())),
glm::vec3(0,0,0),
glm::vec3(0,1,0)
);

  这样,我们可以看到一个以我们观察角度来看是顺时针旋转的正方体(其实是摄像机在逆时针旋转),如果对X 进行 Sin 计算而 Y 进行 Cos 计算的话那么更好相反。

MD不支持视频,我上传了Youtube,点这里看效果

0%