移动方式 & 动作 & 设计
在上一篇文章中我们介绍了如何使用四元数表示旋转,本篇将根据「WebGL Insights - 23.Designing Cameras for WebGL Applications」一文,设计一个可供 3D 引擎使用的,功能完备的 Camera。
移动方式
摄像机按照常用的移动方式可以分成两类:Exploring/tracking 和 Orbiting。 前者固定摄像机位置,常用于第一人称,第三人称视角场景,后者固定 focal point,常用与观察模型的场景。
除此之外,在 Orbiting 类型中,还可以细分出“圆柱体”类型,和通常的球形模式区别就是将 elevation 替换成了距离中心平面的距离:
另外在 RTS 游戏场景下,常用“鸟瞰”模式,摄像机平面平行于地面并保持一定距离:
本文将关注 Tracking 和 Orbiting 这两类。
摄像机动作
learnwebgl - camera_movement 中对于摄像机的动作介绍十分详细,总结下就是分别绕 u v n 轴旋转或者沿这三轴移动:
很自然的,根据移动方式的不同,同一个摄像机动作对应的实现也不同。 我们以 dolly 动作为例,同样都是一个向前向后移动摄像机位置的动作,对于 Orbiting 模式视点不变,而在 Tracking 模式下视点是需要调整的。 以下代码来自 nucleo:
nucleo.Camera.prototype.dolly = function (value) {
var Camera = nucleo.Camera;
// 视线方向
var n = this._forward;
var pos = vec3.clone(this._position);
var step = value * this._dollyingStep;
pos[0] += step * n[0];
pos[1] += step * n[1];
pos[2] += step * n[2];
// 设置摄像机位置
this._setPosition(pos);
if (this.type == Camera.TYPE.ORBITING || this.type == Camera.TYPE.EXPLORING) {
// 视点不变,更新焦距
this._getDistance();
}
else if (this.type == Camera.TYPE.TRACKING) {
// 保持焦距,移动视点
vec3.add(this._focalPoint, pos, this._distanceVector);
}
return this;
};
下面我们重点关注一下旋转动作,结合上一篇文章中介绍过的四元数就应该很容易理解了。
旋转
按照 Orbiting 和 Tracking 模式,每次旋转后调整摄像机位置和视点:
if (this.type == Camera.TYPE.ORBITING || this.type == Camera.TYPE.EXPLORING) {
this._getPosition();
}
else if (this.type == Camera.TYPE.TRACKING) {
this._getFocalPoint();
}
设计
Responsible Camera
Transparent Camera
Landmarks
参考资料
- WebGL Insights - 23.Designing Cameras for WebGL Applications
- Wiki - Angle_of_view
- webglfundamentals - webgl-3d-camera
- voxelent - tutorial-cameras