游戏引擎从零开始(27)-Camera Crontroller

前言

本章节,我们再继续做一点封装,将OrthographicCamera中的部分控制逻辑抽出来,放到OrthograrphicCameraController中,这使得Camera更聚焦、轻量。

代码比较简单,不做过多的说明了,代码中有必要的注释。

正文

OrthographicCamera中增加SetProjection接口,后面用的上。

Sandbox/Hazel/src/Hazel/Renderer/OrthographicCamera.h

c++ 复制代码
public:
    OrthographicCamera(float left, float right, float bottom, float top);
    ...
    void SetProjection(float left, float right, float bottom, float top);

Sandbox/Hazel/src/Hazel/Renderer/OrthographicCamera.cpp

c++ 复制代码
void OrthographicCamera::SetProjection(float left, float right, float bottom, float top) {
    m_ProjectionMatrix = glm::ortho(left, right, bottom, top, -1.0f, 1.0f);
    m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
}

将之前SandBoxApp业务层中一部分逻辑抠出来,内聚到Controller中。

Sandbox/Hazel/src/Hazel/OrthographicCameraController.h

c++ 复制代码
#pragma once

#include "MouseEvent.h"
#include "ApplicationEvent.h"
#include "Timestep.h"
#include "Renderer/OrthographicCamera.h"

namespace Hazel {
    class OrthographicCameraController {
    public:
        OrthographicCameraController(float aspecRato, bool rotation = false);
        void OnUpdate(Timestep ts);
        void OnEvent(Event& e);

        OrthographicCamera& GetCamera(){return m_Camera;}
        const OrthographicCamera& GetCamera() const {return m_Camera;}

    private:
        bool OnMouseScrolled(MouseScrolledEvent& e);
        bool OnWindowsResized(WindowResizeEvent& e);

    private:
        float m_AspectRatio;
        float m_ZoomLevel = 1.0f;
        bool m_Rotation = false;
        glm::vec3 m_CameraPosition;
        float m_CameraRotation = 0.0f;
        float m_CameraMoveSpeed = 5.f;
        float m_CameraRotationSpeed = 180.0f;
        OrthographicCamera m_Camera;
    };

}

Sandbox/Hazel/src/Hazel/OrthographicCameraController.cpp

c++ 复制代码
#include "OrthographicCameraController.h"
#include "Input.h"
#include "KeyCodes.h"
#include "Core.h"

namespace Hazel {

    OrthographicCameraController::OrthographicCameraController(float aspecRato, bool rotation)
        : m_AspectRatio(aspecRato),
        m_Camera(-m_AspectRatio * m_ZoomLevel, m_AspectRatio * m_ZoomLevel, -m_ZoomLevel, m_ZoomLevel),
        m_Rotation(rotation)
    {}

    void OrthographicCameraController::OnUpdate(Timestep ts) {
        if (Hazel::Input::IsKeyPressed(HZ_KEY_A))
            m_CameraPosition.x -= m_CameraMoveSpeed * ts;
        else if (Hazel::Input::IsKeyPressed(HZ_KEY_D))
            m_CameraPosition.x += m_CameraMoveSpeed * ts ;

        if (Hazel::Input::IsKeyPressed(HZ_KEY_W))
            m_CameraPosition.y += m_CameraMoveSpeed * ts ;
        else if (Hazel::Input::IsKeyPressed(HZ_KEY_S))
            m_CameraPosition.y -= m_CameraMoveSpeed * ts ;

        if (m_Rotation) {
            if (Hazel::Input::IsKeyPressed(HZ_KEY_Q))
                m_CameraRotation += m_CameraRotationSpeed * ts;
            if (Hazel::Input::IsKeyPressed(HZ_KEY_E))
                m_CameraRotation -= m_CameraRotationSpeed * ts;
        }

        m_Camera.SetPosition(m_CameraPosition);
        m_CameraMoveSpeed = m_ZoomLevel;
    }

    // 在OnEvent中分发MouseScrolledEvent和WindowResizeEvent事件。
    void OrthographicCameraController::OnEvent(Event &e) {
        EventDispatcher dispatcher(e);
        dispatcher.Dispatch<MouseScrolledEvent>(HZ_BIND_EVENT_FN(OrthographicCameraController::OnMouseScrolled));
        dispatcher.Dispatch<WindowResizeEvent>(HZ_BIND_EVENT_FN(OrthographicCameraController::OnWindowsResized));
    }
    
    // OnMouseScrolled中处理鼠标滚动事件
    bool OrthographicCameraController::OnMouseScrolled(MouseScrolledEvent &e) {
        // mac平台,滚轮向下滚动y-offset为正
        // 则m_ZoomLevel变小,Camera的视野变小意味着场景中的物体放大
        m_ZoomLevel -= e.GetYOffset() * 0.25;
        // m_ZomLevel最小取值为0.25,即放大倍数最大为4倍
        m_ZoomLevel = std::max(m_ZoomLevel, 0.25f);
        m_Camera.SetProjection(-m_AspectRatio * m_ZoomLevel, m_AspectRatio * m_ZoomLevel, -m_ZoomLevel, m_ZoomLevel);
        return false;
    }

    // 实现缩放的逻辑,向上滑动放大,向下滑动缩小,最小比例限制为0.25。
    bool OrthographicCameraController::OnWindowsResized(WindowResizeEvent &e) {
        // 宽高比
        m_AspectRatio = (float)e.GetWidth()/(float)e.GetHeight();
        // 简单处理
        // 相机投影的上下边界不变,宽度按窗口宽高比缩放
        m_Camera.SetProjection(-m_AspectRatio*m_ZoomLevel, m_AspectRatio*m_ZoomLevel, -m_ZoomLevel, m_ZoomLevel);
        return false;
    }
}

SandboxApp中引入CameraController,去掉了Camera的直接引用。

Sandbox/src/SandboxApp.cpp

c++ 复制代码
...
class ExampleLayer : public Hazel::Layer
{
public:
    ExampleLayer()
      : Layer("Example"), m_CameraController(1280.0f / 720.0f)
    {
      m_VertexArray.reset(Hazel::VertexArray::Create());


    void OnUpdate(Hazel::Timestep ts) override
    {
      // Update
      m_CameraController.OnUpdate(ts);

      // Render
      Hazel::RenderCommand::SetClearColor({ 0.1f, 0.1f, 0.1f, 1 });
      Hazel::RenderCommand::Clear();

      Hazel::Renderer::BeginScene(m_CameraController.GetCamera());

      glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(0.1f));

      ImGui::End();
    }

    void OnEvent(Hazel::Event& e) override
    {
      m_CameraController.OnEvent(e);
    }
  private:
    Hazel::ShaderLibrary m_ShaderLibrary;

    Hazel::Ref<Hazel::Texture2D> m_Texture, m_ChernoLogoTexture;

    Hazel::OrthographicCameraController m_CameraController;
    glm::vec3 m_SquareColor = { 0.2f, 0.3f, 0.8f };
  ...
}

如果没问题,滚动鼠标,可以看到场景有缩放效果:

完整代码&总结

完整代码:
github.com/summer-go/H...

总结:

实际上,有些引擎中并不存在CameraController这一层,Camera直接暴露给业务层使用。但我们也看到,有CameraController这一层,代码确实更清爽了一些。工程上,在轻量简洁和模块化封装之间如何平衡,是一个永恒的话题,要根据实际项目来定,将易便的暴露出去,稳定的沉下去。

相关推荐
蒸蒸yyyyzwd12 分钟前
八股学习 MVCC 慢查询优化和 read 过程
c++·八股
APEX真好玩20 分钟前
把高频传感器(IMU)数据封装进 MP4:FFmpeg 私有数据轨实践
c++
晴天的雨.99232 分钟前
[C++算法]盛最多水的容器(双指针算法)
开发语言·c++·算法
布莱克6051 小时前
理解内存泄漏:成因、发现方法与解决策略(C++ 举例)
c语言·c++·内存泄漏
此生决int2 小时前
深入理解C++系列(19)——C++11(上)
开发语言·c++
郝学胜-神的一滴2 小时前
C++20模板元编程 05:吃透变参模板,解锁编译期万能参数能力
服务器·开发语言·c++·windows·vscode
C++ 老炮儿的技术栈11 小时前
我们在设计tcp协议时,要传一个字符串过去,报文:头十长度十内容,是否要把‘\0‘也填入,长度是否包含‘\0‘
开发语言·数据结构·c++·mfc·c
I_belong_to_jesus17 小时前
std::unique_ptr成员函数用法
c++
Tairitsu_H17 小时前
[C++] 拷贝构造还是赋值重载?类默认成员函数细节详解
开发语言·c++·类和对象
汉克老师18 小时前
GESP2026年9月认证C++四级( 第一部分选择题(1~7题)精讲
c++·gesp·小学生·学c++编程