游戏引擎从零开始(20)-移动相机

前言

现在的场景是写死的,相机不能移动,本章节增加键盘响应,对相机增加移动、旋转操作。

代码整理

开始前,我们先整理下代码,将Application中相机的操作、绘制元素、Shader的操作挪到Sandbox中。

现在Application中的代码总共只有70行左右,非常轻量。

修改逻辑参考代码:
github.com/summer-go/H...

相机运动

在OnUpdate方法中,每帧更新一点相机的位置、旋转就形成了动画效果。

相机响应按键

增加up、down、left、right按键处理,控制相机上下左右移动,此时看到的场景向相反方向移动。

增加"A"、"D"按键处理,控制相机逆时针、顺时针旋转,同样,看到的场景向相反方向旋转。

代码修改集中在ExampleLayer中:

Sandbox/src/SandBoxApp.cpp

c++ 复制代码
void OnUpdate() override{

    if (Hazel::Input::IsKeyPressed(HZ_KEY_LEFT))
        m_CameraPosition.x -= m_CameraMoveSpeed ;
    else if (Hazel::Input::IsKeyPressed(HZ_KEY_RIGHT))
        m_CameraPosition.x += m_CameraMoveSpeed ;

    if (Hazel::Input::IsKeyPressed(HZ_KEY_UP))
        m_CameraPosition.y += m_CameraMoveSpeed ;
    else if (Hazel::Input::IsKeyPressed(HZ_KEY_DOWN))
        m_CameraPosition.y -= m_CameraMoveSpeed ;

    if (Hazel::Input::IsKeyPressed(HZ_KEY_A))
        m_CameraRotation += m_CameraRotationSpeed;
    if (Hazel::Input::IsKeyPressed(HZ_KEY_D))
        m_CameraRotation -= m_CameraRotationSpeed;

    Hazel::RenderCommand::SetClearColor({0.45f, 0.55f, 0.60f, 1.00f});
    Hazel::RenderCommand::Clear();

    m_Camera.SetPosition(m_CameraPosition);
    m_Camera.SetRotation(m_CameraRotation);

    Hazel::Renderer::BeginScene(m_Camera);
    Hazel::Renderer::Submit(m_BlueShader,m_SquareVA);
    Hazel::Renderer::Submit(m_Shader, m_VertexArray);
    Hazel::Renderer::EndScene();
}
virtual void OnImGuiRender() override {
}
void OnEvent(Hazel::Event& event) override {
}
private:
    std::shared_ptr<Hazel::Shader> m_Shader;
    std::shared_ptr<Hazel::VertexArray> m_VertexArray;
    std::shared_ptr<Hazel::Shader> m_BlueShader;
    std::shared_ptr<Hazel::VertexArray> m_SquareVA;
    Hazel::OrthographicCamera m_Camera;
    glm::vec3 m_CameraPosition;
    float m_CameraRotation = 0.0f;

    float m_CameraMoveSpeed = 0.03f;
    float m_CameraRotationSpeed = 1.0f;
};

运行正确可以看到效果:

增加Timestep

在OnUpdate里直接更新相机的运动有个问题,相机的运动速度和帧率有关,帧率越高则相机变化的速度越快。这显然不合理,不同的机型、机器的状态不可能都稳定在统一的速度上。如何解决呢?

用update的时间差来控制更新的幅度,引入Timestep,其实就是记录一个时间戳的差。

Sandbox/Hazel/src/Hazel/Application.cpp

c++ 复制代码
void Application::Run() {
    while(m_Running) {
        float time = glfwGetTime();
        Timestep timestep = time - m_LastFrameTime;
        m_LastFrameTime = time;

        for (Layer* layer : m_LayerStack) {
            layer->OnUpdate(timestep);
        }
        m_ImGuiLayer->Begin();
        ...
    }
}

用copy的形式传参,因为Timestep只有一个float变量,copy和传引用、传指针的性能一样,因为传引用和传指针也存在一个指针的copy。

Timestep的实现:

Sandbox/Hazel/src/Hazel/Core/Timestep.h

c++ 复制代码
#pragma once

namespace Hazel {
    class Timestep {
    public:
        Timestep(float time = 0.0f):m_Time(time){}

        operator float() const {return m_Time;}

        float GetSeconds() const {return m_Time;}
        float GetMilliseconds() const {return m_Time * 1000.0f;}
    private:
        float m_Time;
    };
}

注意一个技巧,重载运算符float(),则Timestep可以直接转换成float类型,写代码很方便,也更健壮。

完整代码&总结

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

在开发的过程中,不断的有代码调整的操作,可见好代码并不是一把就写好的,是逐步完善出来的。

相关推荐
山河木马3 小时前
渲染管线-计算得到gl_Position(顶点着色器)之后续GPU流程
javascript·webgl·图形学
花褪残红青杏小10 小时前
Rust图像处理第11节-故障风 RGB 通道偏移:错位错色制造电子故障
rust·webassembly·图形学
SmalBox10 小时前
【节点】[EyeSurfaceTypeDebug节点]原理解析与实际应用
unity3d·游戏开发·图形学
花褪残红青杏小11 小时前
Rust图像处理第10节-浮雕/雕刻滤镜:邻域差值生成凹凸效果
rust·webassembly·图形学
小bo波1 天前
Java Swing 图形用户界面实验 —— 从算术练习到游戏开发的完整实践
java·课程设计·gui·游戏开发·扫雷·swing
apocelipes1 天前
常用编程语言和库的正则表达式性能对比
c语言·c++·python·性能优化·golang·开发工具和环境
SmalBox1 天前
【节点】[CorneaRefraction节点]原理解析与实际应用
unity3d·游戏开发·图形学
花褪残红青杏小1 天前
Rust图像处理第9节-Sobel 边缘检测:第一个真正用卷积的算法
rust·webassembly·图形学
花褪残红青杏小2 天前
Rust图像处理第8节-暗角 & 复古胶片特效:四周衰减中心高亮
rust·webassembly·图形学
SmalBox2 天前
【节点】[CirclePupilAnimation节点]原理解析与实际应用
unity3d·游戏开发·图形学