欢迎光临
我们一直在努力

Building a Simple Engine -- Camera Transformations -- Transformation matrices

相机与变换:变换矩阵

变换矩阵(Transformation Matrices)

在本节中,我们将深入探讨 3D 图形学中使用的变换矩阵,以及它们在渲染管线中的应用方式。

模型 – 视图 – 投影(MVP)管线

顶点从物体空间转换到屏幕空间的过程涉及一系列矩阵乘法,这一过程通常被称为 MVP 管线:

// 完整的变换管线
glm::mat4 MVP = projectionMatrix * viewMatrix * modelMatrix;

下面我们详细解析每个矩阵的作用。

模型矩阵(Model Matrix)

模型矩阵将顶点从物体空间变换到世界空间,用于在世界坐标系中定位、旋转和缩放物体。

glm::mat4 createModelMatrix(
const glm::vec3& position,
const glm::vec3& rotation,
const glm::vec3& scale
) {
glm::mat4 model = glm::mat4(1.0f);

// 按顺序应用变换:缩放 → 旋转 → 平移
model = glm::translate(model, position);

// 绕各轴应用旋转变换
model = glm::rotate(model, glm::radians(rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, glm::radians(rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::rotate(model, glm::radians(rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));

// 应用缩放变换
model = glm::scale(model, scale);

return model;
}

视图矩阵(View Matrix)

视图矩阵将顶点从世界空间变换到视图空间(相机空间),它代表了相机的位置和朝向。

glm::mat4 createViewMatrix(
const glm::vec3& cameraPosition,
const glm::vec3& cameraTarget,
const glm::vec3& upVector
) {
return glm::lookAt(cameraPosition, cameraTarget, upVector);
}

lookAt函数会创建一个视图矩阵,将相机放置在cameraPosition位置,朝向cameraTarget目标点,同时通过upVector定义相机的上方向。

投影矩阵(Projection Matrix)

投影矩阵将顶点从视图空间变换到裁剪空间,它定义了 3D 坐标如何投影到 2D 屏幕上。

透视投影(Perspective Projection)

透视投影模拟了人眼的视觉效果:物体距离越远,显示尺寸越小。

glm::mat4 createPerspectiveMatrix(
float fovY,
float aspectRatio,
float nearPlane,
float farPlane
) {
return glm::perspective(glm::radians(fovY), aspectRatio, nearPlane, farPlane);
}

参数说明:

  • fovY:垂直方向的视野角度(单位:度)
  • aspectRatio:视口的宽高比(宽度 / 高度)
  • nearPlane:近裁剪面的距离
  • farPlane:远裁剪面的距离
正交投影(Orthographic Projection)

正交投影不存在透视畸变,适用于 2D 渲染或技术绘图场景。

glm::mat4 createOrthographicMatrix(
float left,
float right,
float bottom,
float top,
float nearPlane,
float farPlane
) {
return glm::ortho(left, right, bottom, top, nearPlane, farPlane);
}

法向量矩阵(Normal Matrix)

当对物体应用非均匀缩放时,如果直接使用模型矩阵变换法向量,会导致法向量方向出错。法向量矩阵正是为解决这一问题而生:

glm::mat3 createNormalMatrix(const glm::mat4& modelMatrix) {
// 法向量矩阵是模型矩阵左上角3×3子矩阵的逆矩阵的转置
return glm::transpose(glm::inverse(glm::mat3(modelMatrix)));
}

在着色器中应用变换

在 Vulkan 中,我们通常将这些矩阵作为统一变量(uniform)传递给着色器:

// 顶点着色器
#version 450

layout(binding = 0) uniform UniformBufferObject {
mat4 model;
mat4 view;
mat4 proj;
} ubo;

layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inNormal;
layout(location = 2) in vec2 inTexCoord;

layout(location = 0) out vec3 fragNormal;
layout(location = 1) out vec2 fragTexCoord;

void main() {
// 应用MVP变换
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 1.0);

// 使用法向量矩阵变换法向量
mat3 normalMatrix = transpose(inverse(mat3(ubo.model)));
fragNormal = normalMatrix * inNormal;

fragTexCoord = inTexCoord;
}

层级变换(Hierarchical Transformations)

对于存在父子关系的复杂物体或场景,我们需要使用层级变换:

// 父物体变换
glm::mat4 parentModel = createModelMatrix(parentPosition, parentRotation, parentScale);

// 子物体相对于父物体的局部变换
glm::mat4 localModel = createModelMatrix(childLocalPosition, childLocalRotation, childLocalScale);

// 组合变换(子物体的世界空间变换矩阵)
glm::mat4 childWorldModel = parentModel * localModel;

在下一节中,我们将基于这些变换概念,实现一个能够在 3D 场景中自由导航的相机系统。

赞(0)
未经允许不得转载:171主机测评 » Building a Simple Engine -- Camera Transformations -- Transformation matrices
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址