本节主要是为即将要完成的 2D渲染的渲染器创建一个新的 Layer 来使用,首先将 Hazel.h 中的 EntryPoint.h 放到我们的 SandBox 中,因为这个头文件实际上是整个项目的 main 函数,我们后面再进行 Hazel.h 包含的时候会出问题
#pragma once
#include "Hazel.h"
class Sandbox2D : public Hazel::Layer
{
public:
Sandbox2D();
virtual ~Sandbox2D() = default;
virtual void OnAttach() override;
virtual void OnDetach() override;
void OnUpdate(Hazel::Timestep ts) override;
virtual void OnImGuiRender() override;
void OnEvent(Hazel::Event& e) override;
private:
Hazel::OrthographicCameraController m_CameraController;
// Temp
Hazel::Ref<Hazel::VertexArray> m_SquareVA;
Hazel::Ref<Hazel::Shader> m_FlatColorShader;
glm::vec4 m_SquareColor = { 0.2f, 0.3f, 0.8f, 1.0f };
};
SandBox2D Layer 中也是包含了一个 Layer 的基本函数:OnAttach
OnDetach
OnUpdate
OnImGuiRender
OnEvent
然后还创建了一个 CameraController
一个顶点数组和一个 shader
Cpp 文件中:
#include "Sandbox2D.h"
#include "imgui/imgui.h"
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "Platform/OpenGL/OpenGLShader.h"
Sandbox2D::Sandbox2D()
: Layer("Sandbox2D"), m_CameraController(1280.0f / 720.0f)
{
}
void Sandbox2D::OnAttach()
{
m_SquareVA = Hazel::VertexArray::Create(); //之前 Create 函数返回的指针改为了 shared_ptr
float squareVertices[3 * 4] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f
};
Hazel::Ref<Hazel::VertexBuffer> squareVB;
squareVB.reset(Hazel::VertexBuffer::Create(squareVertices, sizeof(squareVertices)));
squareVB->SetLayout({
{ Hazel::ShaderDataType::Float3, "a_Position" }
});
m_SquareVA->AddVertexBuffer(squareVB);
uint32_t squareIndices[6] = { 0, 1, 2, 2, 3, 0 };
Hazel::Ref<Hazel::IndexBuffer> squareIB;
squareIB.reset(Hazel::IndexBuffer::Create(squareIndices, sizeof(squareIndices) / sizeof(uint32_t)));
m_SquareVA->SetIndexBuffer(squareIB);
m_FlatColorShader = Hazel::Shader::Create("assets/shaders/FlatColor.glsl");
}
void Sandbox2D::OnDetach()
{
}
void Sandbox2D::OnUpdate(Hazel::Timestep ts)
{
// 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());
std::dynamic_pointer_cast<Hazel::OpenGLShader>(m_FlatColorShader)->Bind();
std::dynamic_pointer_cast<Hazel::OpenGLShader>(m_FlatColorShader)->UploadUniformFloat4("u_Color", m_SquareColor);
Hazel::Renderer::Submit(m_FlatColorShader, m_SquareVA, glm::scale(glm::mat4(1.0f), glm::vec3(1.5f)));
Hazel::Renderer::EndScene();
}
void Sandbox2D::OnImGuiRender()
{
ImGui::Begin("Settings");
ImGui::ColorEdit4("Square Color", glm::value_ptr(m_SquareColor));
ImGui::End();
}
void Sandbox2D::OnEvent(Hazel::Event& e)
{
m_CameraController.OnEvent(e);
}
在 OnAttach
函数中,创建了一个 VertexArray ,然后创建 VertexBuffer,并存储了 4 个顶点,以及一个 IndexBuffer,
存放了矩形的顶点索引,然后绑定一个 shader.
在OnUpdate
函数中,首先进行 CameraController 的更新,然后进行渲染步骤:clear,BeginScene,BindShader,setUniform,Submit,EndScene。
然后在OnEvent
函数中,将产生的 event 传给 CameraController。
为了更高效率的进行 2D 渲染,需要为 2D Renderer 单独创建属于其的 renderer 以及其他相应的配置,创建 Renderer2D.h
Renderer2D.cpp
#pragma once
#include "OrthographicCamera.h"
namespace Hazel {
class Renderer2D
{
public:
static void Init();
static void Shutdown();
static void BeginScene(const OrthographicCamera& camera);
static void EndScene();
// Primitives
static void DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color);
static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color);
};
}
所有的函数都被定义为 static,是因为我们不希望在创建多个 renderer2D 实例时,每个实例都调用各自的函数,定义为static 之后,函数可以被所有的实例共享。由于 2D Renderer 渲染物体实际上都是通过画2D图形实现的,所以创建了 DrawQuad 函数,专门用于矩形的绘制。
#include "hzpch.h"
#include "Renderer2D.h"
#include "VertexArray.h"
#include "Shader.h"
#include "RenderCommand.h"
#include "Platform/OpenGL/OpenGLShader.h"
namespace Hazel {
struct Renderer2DStorage
{
Ref<VertexArray> QuadVertexArray;
Ref<Shader> FlatColorShader;
};
static Renderer2DStorage* s_Data;
void Renderer2D::Init()
{
s_Data = new Renderer2DStorage();
s_Data->QuadVertexArray = VertexArray::Create();
float squareVertices[3 * 4] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f
};
Ref<VertexBuffer> squareVB;
squareVB = VertexBuffer::Create(squareVertices, sizeof(squareVertices));
squareVB->SetLayout({
{ ShaderDataType::Float3, "a_Position" }
});
s_Data->QuadVertexArray->AddVertexBuffer(squareVB);
uint32_t squareIndices[6] = { 0, 1, 2, 2, 3, 0 };
Ref<IndexBuffer> squareIB;
squareIB = IndexBuffer::Create(squareIndices, sizeof(squareIndices) / sizeof(uint32_t));
s_Data->QuadVertexArray->SetIndexBuffer(squareIB);
s_Data->FlatColorShader = Shader::Create("assets/shaders/FlatColor.glsl");
}
void Renderer2D::Shutdown()
{
delete s_Data;
}
void Renderer2D::BeginScene(const OrthographicCamera& camera)
{
std::dynamic_pointer_cast<OpenGLShader>(s_Data->FlatColorShader)->Bind();
std::dynamic_pointer_cast<OpenGLShader>(s_Data->FlatColorShader)->UploadUniformMat4("u_ViewProjection", camera.GetViewProjectionMatrix());
std::dynamic_pointer_cast<OpenGLShader>(s_Data->FlatColorShader)->UploadUniformMat4("u_Transform", glm::mat4(1.0f));
}
void Renderer2D::EndScene()
{
}
void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color)
{
DrawQuad({ position.x, position.y, 0.0f }, size, color);
}
void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color)
{
std::dynamic_pointer_cast<OpenGLShader>(s_Data->FlatColorShader)->Bind();
std::dynamic_pointer_cast<Hazel::OpenGLShader>(s_Data->FlatColorShader)->UploadUniformFloat4("u_Color", color);
s_Data->QuadVertexArray->Bind();
RenderCommand::DrawIndexed(s_Data->QuadVertexArray);
}
}
这里将之前的 SandBox2D 中的 OnAttach 的部分全部移到 Renderer2D 的 Init 函数中,创建了一个结构体,用于存放 VertexArray 和我们的 shader,创建了一个 static 指针 s_Data 用于进行访问,然后在 Shutdown 中要对其进行delete 避免内存泄漏。BeginScene
中,进行 shader 绑定,uniform 设置,DrawQuad
函数进行颜色设置,然后利用 RenderCommand 函数 DrawIndexed
进行绘制。