Hazel game engine (061) starts 2D batch rendering

If there are errors in the code, terminology, etc. in the text, please correct me

foreword

  • Purpose

    Realize the batch rendering of OpenGL, reduce the calls of OpenGL drawing commands, and use one OpenGL drawing command to draw multiple graphics

  • general idea

    Both CPU and GPU open up a large memory of the same size (in order to store vertex information)

    The index is bound to the index buffer after the corresponding rules are generated when the program is running

    Dynamically generate vertex information (now changed to Drawquad just to determine the position of the graphics vertex)

    Then in Endscene, the dynamically generated vertex data of the CPU is uploaded to the GPU, and then drawn .

key code flow

  • Both CPU and GPU open up a large memory of the same size (in order to store vertex information)

    // 0.在CPU开辟存储s_Data.MaxVertices个的QuadVertex的内存
    s_Data.QuadVertexBufferBase = new QuadVertex[s_Data.MaxVertices];
    
    // 2.创建顶点缓冲区,先在GPU开辟一块s_Data.MaxVertices * sizeof(QuadVertex)大小的内存
    // 与cpu对应大,是为了传输顶点数据
    s_Data.QuadVertexBuffer = VertexBuffer::Create(s_Data.MaxVertices * sizeof(QuadVertex));
    
  • The index is bound to the index buffer after the corresponding rules are generated when the program is running

    (The rule is a Quad composed of 2 triangles. Originally, 2 triangles have a total of 6 vertices. After using the index, the vertices can be reused, thereby reducing to 4 vertices to form a quadrangle)

    // 3.索引缓冲
    //uint32_t flatIndices[] = { 0, 1, 2, 2, 3, 0 };
    uint32_t* quadIndices = new uint32_t[s_Data.MaxIndices];
    
    // 一个quad用6个索引,012 230,456 674
    uint32_t offset = 0;
    for (uint32_t i = 0; i < s_Data.MaxIndices; i += 6) {
          
          
        quadIndices[i + 0] = offset + 0;
        quadIndices[i + 1] = offset + 1;
        quadIndices[i + 2] = offset + 2;
    
        quadIndices[i + 3] = offset + 2;
        quadIndices[i + 4] = offset + 3;
        quadIndices[i + 5] = offset + 0;
    
        offset += 4;
    }
    
    Ref<IndexBuffer> flatIB = IndexBuffer::Create(quadIndices, s_Data.MaxIndices);
    
    // 1.2顶点数组设置索引缓冲区
    s_Data.QuadVertexArray->SetIndexBuffer(flatIB);
    // cpu上传到gpu上了可以删除cpu的索引数据块了
    delete[] quadIndices;
    
  • Dynamically generate vertex information, mainly position, texture coordinates

    void Hazel::Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color)
    {
          
          
        HZ_PROFILE_FUNCTION();
        /
        /
    	/*
    	根据参数position确定当前顶点的位置,应该是基于本地空间
    	注意,并没有计算图形的transform来偏移顶点位置
    	而是手动根据position、size确定一个四方形的四个点的位置
    	*/
        // quad的左下角为起点
        s_Data.QuadVertexBufferPtr->Position = position;
        s_Data.QuadVertexBufferPtr->Color = color;
        s_Data.QuadVertexBufferPtr->TexCoord = {
          
           0.0f, 0.0f };
        s_Data.QuadVertexBufferPtr++;
    
        s_Data.QuadVertexBufferPtr->Position = {
          
           position.x + size.x, position.y, 0.0f };
        s_Data.QuadVertexBufferPtr->Color = color;
        s_Data.QuadVertexBufferPtr->TexCoord = {
          
           1.0f, 0.0f };
        s_Data.QuadVertexBufferPtr++;
    
        s_Data.QuadVertexBufferPtr->Position = {
          
           position.x + size.x, position.y + size.y, 0.0f };
        s_Data.QuadVertexBufferPtr->Color = color;
        s_Data.QuadVertexBufferPtr->TexCoord = {
          
           1.0f, 1.0f };
        s_Data.QuadVertexBufferPtr++;
    
        s_Data.QuadVertexBufferPtr->Position = {
          
           position.x, position.y +size.y , 0.0f };
        s_Data.QuadVertexBufferPtr->Color = color;
        s_Data.QuadVertexBufferPtr->TexCoord = {
          
           0.0f, 1.0f };
        s_Data.QuadVertexBufferPtr++;
    
        s_Data.QuadIndexCount += 6;// 每一个quad用6个索引
    }
    
  • Then in Endscene, upload the dynamically generated vertex data (mainly position information) of the CPU to the GPU, and then draw it out

    void Hazel::Renderer2D::EndScene()
    {
          
          
        HZ_PROFILE_FUNCTION();
    
        // 计算当前绘制需要多少个顶点数据
        uint32_t dataSize = (uint8_t*)s_Data.QuadVertexBufferPtr - (uint8_t*)s_Data.QuadVertexBufferBase;
        // 截取部分CPU的顶点数据上传OpenGL
        s_Data.QuadVertexBuffer->SetData(s_Data.QuadVertexBufferBase, dataSize);
    
        Flush();
    }
    
    void Renderer2D::Flush()
    {
          
          
        RenderCommand::DrawIndexed(s_Data.QuadVertexArray, s_Data.QuadIndexCount);
    }
    ......
    void OpenGLVertexBuffer::SetData(const void* data, uint32_t size)
    {
          
          
        glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
        // 截取部分CPU的顶点数据上传OpenGL
        glBufferSubData(GL_ARRAY_BUFFER, 0, size, data);
    }
    
  • Sandbox2D

    Hazel::Renderer2D::DrawQuad({
          
           -1.0f, 0.0f }, {
          
           0.8f,0.8f }, m_FlatColor);
    Hazel::Renderer2D::DrawQuad({
          
           0.5f, -0.5f }, {
          
           0.5f, 0.8f }, {
          
          0.2f, 0.8f, 0.9f, 1.0f});
    
  • Glsl code

    #type vertex
    #version 330 core
    
    layout(location = 0) in vec3 a_Position;
    layout(location = 1) in vec4 a_Color;
    layout(location = 2) in vec2 a_TexCoord;
    
    uniform mat4 u_ViewProjection;
    // uniform mat4 u_Transform;
    
    out vec4 v_Color;
    out vec2 v_TexCoord;
    
    void main() {
          
          
    	v_Color = a_Color;
    	v_TexCoord = a_TexCoord;
        // 由规则动态生成的顶点位置(基于本地空间)没有涉及transform变换顶点位置
        // gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0); 
    	gl_Position = u_ViewProjection * vec4(a_Position, 1.0);
    }
    #type fragment
    #version 330 core
    
    layout(location = 0) out vec4 color;
    
    in vec4 v_Color;
    in vec2 v_TexCoord;
    
    uniform vec4 u_Color;
    uniform float u_TilingFactor;
    
    uniform sampler2D u_Texture;
    
    void main() {
          
          
    	color = v_Color;
    }
    

result

Please add a picture description

full code

Renderer2D.cpp
#include "hzpch.h"
#include "Renderer2D.h"
#include "VertexArray.h"
#include "Buffer.h"
#include "Shader.h"
#include "Texture.h"
#include "RenderCommand.h"
#include <glm/gtc/matrix_transform.hpp>

namespace Hazel {
    
    
	struct QuadVertex {
    
    
		glm::vec3 Position;
		glm::vec4 Color;
		glm::vec2 TexCoord;
	};
    // 包含顶点的各个信息
	struct Renderer2DData{
    
    
		const uint32_t MaxQuads = 10000;
		const uint32_t MaxVertices = MaxQuads * 4;
		const uint32_t MaxIndices = MaxQuads * 6;

		Ref<VertexArray> QuadVertexArray;
		Ref<VertexBuffer> QuadVertexBuffer;
		Ref<Shader> TextureShader;
		Ref<Texture2D> WhiteTexture;

		uint32_t QuadIndexCount = 0;
		QuadVertex* QuadVertexBufferBase = nullptr;
		QuadVertex* QuadVertexBufferPtr = nullptr;
	};
	static Renderer2DData s_Data;
	void Hazel::Renderer2D::Init()
	{
    
    
		HZ_PROFILE_FUNCTION();

		// 0.在CPU开辟存储s_Data.MaxVertices个的QuadVertex的内存
		s_Data.QuadVertexBufferBase = new QuadVertex[s_Data.MaxVertices];

		// 1.创建顶点数组
		s_Data.QuadVertexArray = VertexArray::Create();

		// 2.创建顶点缓冲区,先在GPU开辟一块s_Data.MaxVertices * sizeof(QuadVertex)大小的内存
		// 与cpu对应大,是为了传输顶点数据
		s_Data.QuadVertexBuffer = VertexBuffer::Create(s_Data.MaxVertices * sizeof(QuadVertex));

		// 2.1设置顶点缓冲区布局
		s_Data.QuadVertexBuffer->SetLayout({
    
    
			{
    
    Hazel::ShaderDataType::Float3, "a_Position"},
			{
    
    Hazel::ShaderDataType::Float4, "a_Color"},
			{
    
    Hazel::ShaderDataType::Float2, "a_TexCoord"}
			});

		// 1.1顶点数组添加顶点缓冲区,并且在这个缓冲区中设置布局
		s_Data.QuadVertexArray->AddVertexBuffer(s_Data.QuadVertexBuffer);

		// 3.索引缓冲
		//uint32_t flatIndices[] = { 0, 1, 2, 2, 3, 0 };
		uint32_t* quadIndices = new uint32_t[s_Data.MaxIndices];
		
		// 一个quad用6个索引,012 230,456 674
		uint32_t offset = 0;
		for (uint32_t i = 0; i < s_Data.MaxIndices; i += 6) {
    
    
			quadIndices[i + 0] = offset + 0;
			quadIndices[i + 1] = offset + 1;
			quadIndices[i + 2] = offset + 2;
										
			quadIndices[i + 3] = offset + 2;
			quadIndices[i + 4] = offset + 3;
			quadIndices[i + 5] = offset + 0;

			offset += 4;
		}

		Ref<IndexBuffer> flatIB = IndexBuffer::Create(quadIndices, s_Data.MaxIndices);

		// 1.2顶点数组设置索引缓冲区
		s_Data.QuadVertexArray->SetIndexBuffer(flatIB);
		// cpu上传到gpu上了可以删除cpu的索引数据块了
		delete[] quadIndices;

		//s_Data.FlatColorShader = (Hazel::Shader::Create("assets/shaders/FlatColor.glsl"));

		// 纹理的shader
		s_Data.TextureShader = Shader::Create("assets/shaders/Texture.glsl");
		s_Data.TextureShader->SetInt("u_Texture", 0);

		// 创建一个白色Texture
		s_Data.WhiteTexture = Texture2D::Create(1, 1);
		uint32_t whiteTextureData = 0xffffffff;
		s_Data.WhiteTexture->SetData(&whiteTextureData, sizeof(uint32_t));
	}

	void Hazel::Renderer2D::Shutdown()
	{
    
    
		HZ_PROFILE_FUNCTION();

	}

	void Hazel::Renderer2D::BeginScene(const OrthographicCamera& camera)
	{
    
    
		HZ_PROFILE_FUNCTION();

		s_Data.TextureShader->Bind();		// 绑定shader
		s_Data.TextureShader->SetMat4("u_ViewProjection", camera.GetViewProjectionMatrix());

		// 相当于初始化此帧要绘制的索引数量,上传的顶点数据
		s_Data.QuadIndexCount = 0;
		// 指针赋予
		s_Data.QuadVertexBufferPtr = s_Data.QuadVertexBufferBase;
	}

	void Hazel::Renderer2D::EndScene()
	{
    
    
		HZ_PROFILE_FUNCTION();

		// 计算当前绘制需要多少个顶点数据
		uint32_t dataSize = (uint8_t*)s_Data.QuadVertexBufferPtr - (uint8_t*)s_Data.QuadVertexBufferBase;
		// 截取部分CPU的顶点数据上传OpenGL
		s_Data.QuadVertexBuffer->SetData(s_Data.QuadVertexBufferBase, dataSize);

		Flush();
	}

	void Renderer2D::Flush()
	{
    
    
		RenderCommand::DrawIndexed(s_Data.QuadVertexArray, s_Data.QuadIndexCount);
	}

	void Hazel::Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color)
	{
    
    
		DrawQuad({
    
     position.x, position.y, 0.0f }, size, color);
	}

	void Hazel::Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color)
	{
    
    
		HZ_PROFILE_FUNCTION();

		// quad的左下角为起点
		s_Data.QuadVertexBufferPtr->Position = position;
		s_Data.QuadVertexBufferPtr->Color = color;
		s_Data.QuadVertexBufferPtr->TexCoord = {
    
     0.0f, 0.0f };
		s_Data.QuadVertexBufferPtr++;

		s_Data.QuadVertexBufferPtr->Position = {
    
     position.x + size.x, position.y, 0.0f };
		s_Data.QuadVertexBufferPtr->Color = color;
		s_Data.QuadVertexBufferPtr->TexCoord = {
    
     1.0f, 0.0f };
		s_Data.QuadVertexBufferPtr++;

		s_Data.QuadVertexBufferPtr->Position = {
    
     position.x + size.x, position.y + size.y, 0.0f };
		s_Data.QuadVertexBufferPtr->Color = color;
		s_Data.QuadVertexBufferPtr->TexCoord = {
    
     1.0f, 1.0f };
		s_Data.QuadVertexBufferPtr++;

		s_Data.QuadVertexBufferPtr->Position = {
    
     position.x, position.y +size.y , 0.0f };
		s_Data.QuadVertexBufferPtr->Color = color;
		s_Data.QuadVertexBufferPtr->TexCoord = {
    
     0.0f, 1.0f };
		s_Data.QuadVertexBufferPtr++;

		s_Data.QuadIndexCount += 6;// 每一个quad用6个索引
		//s_Data.TextureShader->SetFloat4("u_Color", color);
		//s_Data.TextureShader->SetFloat("u_TilingFactor", 1.0f);
		// 绑定纹理
		//s_Data.WhiteTexture->Bind();

		// 设置transform
		/*glm::mat4 tranform = glm::translate(glm::mat4(1.0f), position) *
			glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f });

		s_Data.TextureShader->SetMat4("u_Transform", tranform);

		s_Data.QuadVertexArray->Bind();		// 绑定顶点数组
		RenderCommand::DrawIndexed(s_Data.QuadVertexArray);*/
	}
	void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const Ref<Texture2D>& texture, float tilingFactor, const glm::vec4& tintColor)
	{
    
    
		DrawQuad({
    
     position.x, position.y, 0.0f }, size, texture, tilingFactor, tintColor);
	}
	void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref<Texture2D>& texture, float tilingFactor, const glm::vec4& tintColor)
	{
    
    
		HZ_PROFILE_FUNCTION();

		s_Data.TextureShader->SetFloat4("u_Color", tintColor);
		s_Data.TextureShader->SetFloat("u_TilingFactor", tilingFactor);
		// 绑定纹理
		texture->Bind();

		// 设置transform
		glm::mat4 tranform = glm::translate(glm::mat4(1.0f), position) *
			glm::scale(glm::mat4(1.0f), {
    
     size.x, size.y, 1.0f });

		s_Data.TextureShader->SetMat4("u_Transform", tranform);

		s_Data.QuadVertexArray->Bind();		// 绑定顶点数组
		RenderCommand::DrawIndexed(s_Data.QuadVertexArray);
	}
	void Renderer2D::DrawrRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const glm::vec4& color)
	{
    
    
		DrawrRotatedQuad({
    
    position.x, position.y, 0.0f}, size, rotation, color);
	}
	void Renderer2D::DrawrRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const glm::vec4& color)
	{
    
    
		HZ_PROFILE_FUNCTION();

		s_Data.TextureShader->SetFloat4("u_Color", color);
		s_Data.TextureShader->SetFloat("u_TilingFactor", 1.0f);

		// 绑定纹理
		s_Data.WhiteTexture->Bind();

		// 设置transform
		glm::mat4 tranform = glm::translate(glm::mat4(1.0f), position) *
			glm::rotate(glm::mat4(1.0f), rotation, {
    
     0.0f, 0.0f, 1.0f }) *
			glm::scale(glm::mat4(1.0f), {
    
     size.x, size.y, 1.0f });

		s_Data.TextureShader->SetMat4("u_Transform", tranform);

		s_Data.QuadVertexArray->Bind();		// 绑定顶点数组
		RenderCommand::DrawIndexed(s_Data.QuadVertexArray);
	}
	void Renderer2D::DrawrRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const Ref<Texture2D>& texture, float tilingFactor, const glm::vec4& tintColor)
	{
    
    
		DrawrRotatedQuad({
    
     position.x, position.y, 0.0f }, size, rotation, texture, tilingFactor, tintColor);
	}
	void Renderer2D::DrawrRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const Ref<Texture2D>& texture, float tilingFactor, const glm::vec4& tintColor)
	{
    
    
		HZ_PROFILE_FUNCTION();

		s_Data.TextureShader->SetFloat4("u_Color", tintColor);
		s_Data.TextureShader->SetFloat("u_TilingFactor", tilingFactor);
		// 绑定纹理
		texture->Bind();

		// 设置transform
		glm::mat4 tranform = glm::translate(glm::mat4(1.0f), position) *
			glm::rotate(glm::mat4(1.0f), rotation, {
    
     0.0f, 0.0f, 1.0f }) *
			glm::scale(glm::mat4(1.0f), {
    
     size.x, size.y, 1.0f });

		s_Data.TextureShader->SetMat4("u_Transform", tranform);

		s_Data.QuadVertexArray->Bind();		// 绑定顶点数组
		RenderCommand::DrawIndexed(s_Data.QuadVertexArray);
	}
}

Guess you like

Origin blog.csdn.net/qq_34060370/article/details/131882930