在本篇笔记中,我们将深入探讨Horse3D引擎中的摄像机实现,以及如何通过摄像机将三维世界呈现在屏幕上。摄像机是三维渲染中不可或缺的一部分,它决定了我们从哪个角度、以何种方式观察三维场景。我们将从摄像机的数学基础、实现细节以及实际应用三个方面展开讲解。


一、项目背景与目标

Horse3D引擎的渲染内核基于Qt与OpenGL开发,致力于提供一个功能强大且易于使用的三维渲染解决方案。本项目不提供图形化的编辑器,而是以SDK的形式对外提供接口,方便开发者根据需求进行扩展和定制。在API设计上,我们参考了Three.js与Unity等主流渲染引擎,力求在功能和易用性上达到行业标准。

在本篇中,我们将实现一个支持正交投影和透视投影的摄像机类(Camera),并将其应用到实际的渲染场景中。


二、摄像机的核心功能

1. 视图矩阵(View Matrix)

视图矩阵的作用是将三维世界的坐标系转换为以摄像机为原点的坐标系。通过视图矩阵,我们可以将场景中的所有物体从世界坐标系转换到摄像机的视角坐标系。

在数学上,视图矩阵可以通过以下公式计算:

View Matrix = LookAt ( e y e , t a r g e t , u p ) \text{View Matrix} = \text{LookAt}(eye, target, up) View Matrix=LookAt(eye,target,up)

其中:

  • eye 是摄像机的位置。
  • target 是摄像机注视的目标点。
  • up 是摄像机的上方向向量。

2. 投影矩阵(Projection Matrix)

投影矩阵的作用是将三维空间中的物体投影到二维屏幕上。Horse3D引擎支持两种投影方式:

  • 正交投影(Orthographic Projection) :适用于需要保持物体比例不变的场景,例如工程制图。
  • 透视投影(Perspective Projection) :模拟人类的视觉效果,物体越远越小。

投影矩阵的计算公式如下:

正交投影

( 2 r i g h t − l e f t 0 0 0 0 2 t o p − b o t t o m 0 0 0 0 − 2 f a r − n e a r 0 0 0 0 1 ) \begin{pmatrix} \frac{2}{right - left} & 0 & 0 & 0 \\ 0 & \frac{2}{top - bottom} & 0 & 0 \\ 0 & 0 & \frac{-2}{far - near} & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix} rightleft20000topbottom20000farnear200001

透视投影

( 2 ⋅ n e a r r i g h t − l e f t 0 0 0 0 2 ⋅ n e a r t o p − b o t t o m 0 0 0 0 f a r + n e a r f a r − n e a r 2 ⋅ f a r ⋅ n e a r f a r − n e a r 0 0 − 1 0 ) \begin{pmatrix} \frac{2 \cdot near}{right - left} & 0 & 0 & 0 \\ 0 & \frac{2 \cdot near}{top - bottom} & 0 & 0 \\ 0 & 0 & \frac{far + near}{far - near} & \frac{2 \cdot far \cdot near}{far - near} \\ 0 & 0 & -1 & 0 \end{pmatrix} rightleft2near0000topbottom2near0000farnearfar+near100farnear2farnear0


三、Camera类的实现细节

1. 类结构与成员变量

class Camera {
private:
    CameraEnum m_cameraEnum; // 摄像机类型
    QMatrix4x4 u_lookat;     // 视图矩阵
    QMatrix4x4 u_project;    // 投影矩阵
    QVector3D m_eye;         // 摄像机位置
    QVector3D m_target;      // 摄像机目标点
    QVector3D m_up;          // 摄像机上方向
    float m_left, m_right;   // 左右边界
    float m_bottom, m_top;   // 上下边界
    float m_nearPlane, m_farPlane; // 近远平面
};

2. 核心方法

(1) 更新视图矩阵

void Camera::updateLookat() {
    u_lookat = QMatrix4x4::lookAt(m_eye, m_target, m_up);
}

(2) 更新投影矩阵

void Camera::updateProject() {
    if (m_cameraEnum == ORTHO) {
        u_project = QMatrix4x4::ortho(m_left, m_right, m_bottom, m_top, m_nearPlane, m_farPlane);
    } else {
        u_project = QMatrix4x4::frustum(m_left, m_right, m_bottom, m_top, m_nearPlane, m_farPlane);
    }
}

(3) 应用摄像机到着色器

void Camera::useCamera(QOpenGLShaderProgram* shaderProgram) {
    shaderProgram->setUniformValue("u_lookat", u_lookat);
    shaderProgram->setUniformValue("u_project", u_project);
}

3. 静态工厂方法

为了方便使用,Camera类提供了两个静态方法来创建不同类型的摄像机实例:

static Camera* ortho(const QVector3D& eye, const QVector3D& target, const QVector3D& up, 
                     float left, float right, float bottom, float top, float nearPlane, float farPlane);

static Camera* frustum(const QVector3D& eye, const QVector3D& target, const QVector3D& up, 
                       float left, float right, float bottom, float top, float nearPlane, float farPlane);

四、实际应用案例

1. 创建摄像机

在实际应用中,我们可以通过以下代码创建一个透视投影摄像机:

m_camera = Camera::frustum(
    QVector3D(1.0f, 0.0f, -1.0f), // 摄像机位置
    QVector3D(0.0f, 0.0f, 0.0f),  // 目标点
    QVector3D(0.0f, 1.0f, 0.0f),  // 上方向
    -0.2f, 0.2f,                  // 左右边界
    -0.1f, 0.1f,                  // 上下边界
    0.1f, 100.0f                  // 近远平面
);

2. 应用摄像机到渲染流程

在渲染循环中,我们需要将摄像机的视图和投影矩阵传递给着色器:

void FerghanaScreen::paintGL() {
    glClear(GL_COLOR_BUFFER_BIT);
    material->useMaterial(m_camera); // 将摄像机矩阵传递给着色器
    quadrangle->useGeometry(this);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}

着色器代码如下:

#version 450 core
layout (location = 0) in vec3 a_position;
layout (location = 1) in vec2 a_texcoord;

uniform mat4 u_lookat;
uniform mat4 u_project;

out vec2 v_texcoord;

void main() {
    v_texcoord = a_texcoord;
    gl_Position = u_project * u_lookat * vec4(a_position, 1.0);
}

五、总结与展望

通过本篇的讲解,我们实现了Horse3D引擎中的摄像机功能,包括视图矩阵和投影矩阵的计算与应用。这一功能为我们正式进入三维世界奠定了基础。

未来,我们计划在以下方面对摄像机功能进行扩展:

  1. 支持更多的投影类型(如鱼眼投影)。
  2. 实现摄像机的动画与平滑移动。
  3. 增加摄像机的调试工具,方便开发者调整参数。

如果你对Horse3D引擎感兴趣,欢迎访问我们的GitHubGitee仓库,参与我们的开发与讨论!


效果图:
在这里插入图片描述


参考文献:

【1†source】基于OpenGL封装摄像机类:视图矩阵与透视矩阵的实现
链接:https://blog.csdn.net/2503_92624912/article/details/151211170

【2†source】投影矩阵:计算机图形学中的三维到二维转换
链接:https://blog.csdn.net/2503_92624912/article/details/151157507

【3†source】深度解析游戏引擎中的相机:视图矩阵
链接:https://blog.csdn.net/2503_92624912/article/details/150591762

【4†source】Horse3D游戏引擎研发笔记(一):从使用Qt的OpenGL库绘制三角形开始
链接:https://blog.csdn.net/2503_92624912/article/details/150006641

【5†source】Horse3D游戏引擎研发笔记(二):基于QtOpenGL使用仿Three.js的BufferAttribute结构重构三角形绘制
链接:https://blog.csdn.net/2503_92624912/article/details/150063706

【6†source】Horse3D游戏引擎研发笔记(三):使用QtOpenGL的Shader编程绘制彩色三角形
链接:https://blog.csdn.net/2503_92624912/article/details/150114327

【7†source】Horse3D游戏引擎研发笔记(四):在QtOpenGL下仿three.js,封装EBO绘制四边形
链接:https://blog.csdn.net/2503_92624912/article/details/150235885

【8†source】Horse3D游戏引擎研发笔记(五):在QtOpenGL环境下,仿three.js的BufferGeometry管理VAO和EBO绘制四边形
链接:https://blog.csdn.net/2503_92624912/article/details/150400945

【9†source】Horse3D游戏引擎研发笔记(六):在QtOpenGL环境下,仿Unity的材质管理Shader绘制四边形
链接:https://blog.csdn.net/2503_92624912/article/details/150451239

【10†source】Horse3D游戏引擎研发笔记(七):在QtOpenGL环境下,使用改进的Uniform变量管理方式绘制多彩四边形
链接:https://blog.csdn.net/2503_92624912/article/details/150563946

【11†source】Horse3D游戏引擎研发笔记(八):在QtOpenGL环境下,按需加载彩虹四边形的顶点属性
链接:https://blog.csdn.net/2503_92624912/article/details/150774956

【12†source】Horse3D游戏引擎研发笔记(九):使用现代图形引擎的元数据管理纹理创建过程
链接:https://blog.csdn.net/2503_92624912/article/details/151160306

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐