前言
本章节,我们再继续做一点封装,将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这一层,代码确实更清爽了一些。工程上,在轻量简洁和模块化封装之间如何平衡,是一个永恒的话题,要根据实际项目来定,将易便的暴露出去,稳定的沉下去。