相机矩阵
在 UNIGINE 中,相机有 2 个矩阵:view 和 projection。它们用于将图像从相机渲染到视口.
在进入相机矩阵的主要方面之前,有必要了解 UNIGINE 使用的坐标系的特性,并刷新用于顶点渲染的向量空间和变换矩阵的一般知识。
坐标系#
UNIGINE 中的 3D 空间由右手笛卡尔坐标系表示:X 和 Y 轴形成一个水平面,Z 轴指向上方。
轴和方向#
- +Y 轴被认为是向上的方向。
- -Z 轴被认为是向前的方向。
带有默认恒等变换矩阵的相机向下看:
使用路线#
如您所见,节点和相机的方向向量不同。例如,如果需要获取节点的前向方向,则应为其变换矩阵调用 getAxisY() 方法:
// get the node transformation matrix
Mat4 t = node->getWorldTransform();
// get the node "forward" vector from the matrix
vec3 node_forward = t.getAxisY();
如果您需要获得相机的前进方向,您应该为其变换矩阵调用 -getAxisZ() 方法:
// get the inverse modelview matrix as it is equal to the world transformation one
mat4 camera_transform = camera->getIModelview();
// get the camera "forward" vector from the matrix
vec3 camera_forward = -camera_transform.getAxisZ(); // the negative Z vector will be returned
但是,相机可以设置为玩家节点.在这种情况下,如果您像任何其他节点一样简单地调用 getAxisY(),您将获得相机的向上方向。为避免这种情况,请执行以下操作:
// get the node transformation matrix
Mat4 t = node->getWorldTransform();
// get the "forward" vector from the matrix
vec3 forward = vec3(node->isPlayer() ? -t.getAxisZ() : t.getAxisY());
节点/相机的前进方向(如果设置为播放器节点)也可以使用Node::getDirection()/getWorldDirection()方法获得:
vec3 forward = node->getDirection(node->isPlayer() ? Math::AXIS_NZ : Math::AXIS_Y);
向量空间和变换矩阵#
有以下向量空间:
- Local space 是一个空间,其中一个对象的所有顶点都是相对于该对象的中心定义的。
- World space 是一个空间,其中对象的所有顶点都是相对于世界中心定义的。
- View space 是一个空间,其中对象的所有顶点都是相对于相机定义的。
- Clip space 是一个空间,其中对象的所有顶点都定义在每个轴的 [-1;1] 维度的长方体中。顶点的 Z 坐标指定了顶点离屏幕的距离。
- Screen space 是一个空间,其中对象的所有顶点都被展平并具有屏幕坐标。
渲染顶点时,它按以下顺序从一个空间转换到另一个空间:
用于在空间之间进行变换的矩阵如下:
-
世界变换矩阵存储对象相对于世界原点的变换。该矩阵用于将对象的顶点从局部空间转换到世界空间:矩阵乘以对象的每个顶点。
在 UNIGINE 中,当节点被添加到世界中时,这种转换会自动执行。当一个节点作为另一个节点的子节点添加到世界中时,它还有一个本地变换矩阵,用于存储对象相对于其父节点的变换。为了将这样一个对象的局部变换矩阵变换到世界一,对象的局部变换矩阵乘以父对象的局部变换矩阵。要获得有关局部和世界变换矩阵的更多信息,请查看矩阵层次结构章节。
-
查看矩阵用于将对象的顶点从世界空间转换到视图空间。
在 UNIGINE 中,视图矩阵称为 modelview。 - 投影矩阵用于将对象的顶点从视图空间转换到裁剪空间。
每个加入世界的节点都有世界变换矩阵。但是,将此矩阵传递给着色器进行顶点渲染是不合理的:由于双浮点坐标转换会导致精度损失。为此,在 UNIGINE 中,节点首先转换到视图空间:世界转换矩阵和视图矩阵的乘积在 CPU 上计算并传递给着色器。这样的矩阵称为 Modelview(按其一般含义)。
因此,对象顶点坐标的变换可以用以下公式表示:
VertexClip = ProjectionMatrix * ModelviewMatrix * VertexLocal
这里的 ModelviewMatrix 是世界变换矩阵和视图矩阵的乘积。矩阵乘法的顺序是从右到左读取的。
查看矩阵#
在 UNIGINE 中,View 矩阵是4x4 矩阵,用于控制相机查看场景的方式。这查看矩阵等于逆相机世界变换矩阵:它存储相机在世界空间中的位置和旋转。
矩阵用于将对象的顶点从世界空间转换到视图空间(顶点坐标相对于相机原点设置):相机的视图矩阵乘以对象的世界变换矩阵,然后乘以得到的矩阵通过对象的顶点。
世界空间中的物体和相机 |
视图空间中的对象 |
投影矩阵#
投影矩阵是一个矩阵,用于定义顶点在屏幕上的呈现方式。投影矩阵的值取决于投影类型:
默认情况下,相机的投影矩阵不存储屏幕的纵横比(宽度到高度):自动为当前视口执行纵横比校正。如果进行了手动纵横比校正,则自动纵横比校正必须禁用视口以避免错误结果。
如果更改 FOV(或正交投影的宽度和高度)、近剪裁平面和远剪裁平面,矩阵将更新。
投影矩阵用于将对象的顶点从 view space 转换为 clip space。该空间由每个轴的尺寸为 [-1;1] 的长方体表示,用于裁剪顶点:该体积内的所有顶点都将在屏幕上呈现。在这个空间中,每个顶点的 Z 坐标指定了一个顶点离屏幕的距离。
然后使用透视分割将裁剪空间中的顶点坐标自动转换为归一化的设备坐标。将这些坐标映射到屏幕空间是通过使用存储以下内容的视口变换向量在 GPU 上执行的:
(width, height, 1/width, 1/height)
相机矩阵模拟器#
查看以下电子表格以全面了解 UNIGINE 中相机矩阵的处理方式。它显示了世界变换、视图和投影矩阵影响可用于调试目的的顶点坐标的方式。