Hazel Game Engine (063) optimized batch processing and painting rotation Quad

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

foreword

  • Problems left by batch processing written by 062 and 061

    1. Batch does not have a function to handle quad rotation
    2. The 062 061 designed vertex position is based on its own space, and has not been transformed to transform the position, so there is no rotation effect
  • What this section does

    1. Handle Quad rotation functions

    2. Calculate the vertex position on the CPU and transform it to the world space through the transform matrix (translation, scaling, rotation)

      Unlike before 060, converting vertices from local space to world space was run on the GPU (GLSL code).

  • process:

    1. Give all quads an initial position at the origin ( local space )

    2. Then accept the rotation angle, use the initial position transform matrix = translation * rotation * scaling, and then multiply the vertex to transform to the world space

      (Note that the order of writing code is: translation * scaling * rotation, but the reading order is: read from right to left, first zoom, then rotate and finally translate)

    3. Upload the final world space position to GLSL's vertex shader stage

key place

Renderer2D.cpp

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();

    constexpr glm::vec4 color = {
    
     1.0f, 1.0f, 1.0f, 1.0f };

    float textureIndex = 0.0f;
    for (uint32_t i = 1; i < s_Data.TextureSlotIndex; i++)
    {
    
    
        // 当前纹理,如果已经存储在纹理槽,就直接读取
        if (*s_Data.TextureSlots[i].get() == *texture.get()) {
    
    
            textureIndex = (float)i;
            break;
        }
    }
    if (textureIndex == 0.0f) {
    
    
        textureIndex = (float)s_Data.TextureSlotIndex;
        s_Data.TextureSlots[s_Data.TextureSlotIndex] = texture;
        s_Data.TextureSlotIndex++;// 记得++
    }
    // 设置transform ///
    glm::mat4 tranform = glm::translate(glm::mat4(1.0f), position) *
        glm::rotate(glm::mat4(1.0f), glm::radians(rotation), {
    
     0.0f, 0.0f, 1.0f }) *
        glm::scale(glm::mat4(1.0f), {
    
     size.x, size.y, 1.0f });
	///
    // 从局部空间转换到世界空间///
    // quad的左下角为起点///
    s_Data.QuadVertexBufferPtr->Position = tranform * s_Data.QuadVertexPosition[0];
    s_Data.QuadVertexBufferPtr->Color = color;
    s_Data.QuadVertexBufferPtr->TexCoord = {
    
     0.0f, 0.0f };
    s_Data.QuadVertexBufferPtr->TexIndex = textureIndex;
    s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor;
    s_Data.QuadVertexBufferPtr++;

    s_Data.QuadVertexBufferPtr->Position = tranform * s_Data.QuadVertexPosition[1];
    s_Data.QuadVertexBufferPtr->Color = color;
    s_Data.QuadVertexBufferPtr->TexCoord = {
    
     1.0f, 0.0f };
    s_Data.QuadVertexBufferPtr->TexIndex = textureIndex;
    s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor;
    s_Data.QuadVertexBufferPtr++;

    s_Data.QuadVertexBufferPtr->Position = tranform * s_Data.QuadVertexPosition[2];
    s_Data.QuadVertexBufferPtr->Color = color;
    s_Data.QuadVertexBufferPtr->TexCoord = {
    
     1.0f, 1.0f };
    s_Data.QuadVertexBufferPtr->TexIndex = textureIndex;
    s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor;
    s_Data.QuadVertexBufferPtr++;

    s_Data.QuadVertexBufferPtr->Position = tranform * s_Data.QuadVertexPosition[3];
    s_Data.QuadVertexBufferPtr->Color = color;
    s_Data.QuadVertexBufferPtr->TexCoord = {
    
     0.0f, 1.0f };
    s_Data.QuadVertexBufferPtr->TexIndex = textureIndex;
    s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor;
    s_Data.QuadVertexBufferPtr++;

    s_Data.QuadIndexCount += 6;// 每一个quad用6个索引
}

Sandbox2D.cpp

void Sandbox2D::OnUpdate(Hazel::Timestep ts)
{
    
    
	HZ_PROFILE_FUNCTION();

	m_CameraController.OnUpdate(ts);
	{
    
    
		HZ_PROFILE_SCOPE("Renderer Prep");
		Hazel::RenderCommand::SetClearColor({
    
     0.1f, 0.1f, 0.1f, 1 });
		Hazel::RenderCommand::Clear();
	}
	{
    
    
		HZ_PROFILE_SCOPE("Renderer Draw");

		static float rotation = 0.0f;
		rotation += ts * 50.0f;

		Hazel::Renderer2D::BeginScene(m_CameraController.GetCamera());
		Hazel::Renderer2D::DrawrRotatedQuad({
    
     1.0f, 0.5f }, {
    
     0.8f, 0.8f },30.0f, m_FlatColor);
		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});
        // 棋盘纹理背景
		Hazel::Renderer2D::DrawQuad({
    
     0.0f, 0.0f, -0.1f }, {
    
     10.0f, 10.0f }, m_SquareTexture, 10.0f);
        /
        // 批处理加上会旋转的Quad//
		Hazel::Renderer2D::DrawrRotatedQuad({
    
     -0.5f, -0.5f, 0.0f }, {
    
     1.0f, 1.0f }, rotation, m_SquareTexture, 20.0f);
		Hazel::Renderer2D::EndScene();
	}
}

piece of cake

When the DrawQuad function is modified to multiply the vertices of the quad by the transform matrix, the graphics drawn by the previous code will deviate from

deviate from

result

Please add a picture description

Batch Rendering Summary

  • There is a structure containing various information of vertices (vertex position, color, texture, normal)

    1. First create a large array for this structure on the CPU

    2. There are two variables that record this array

    3. One variable is the base position of the array

    4. One variable is the record where the last vertex is stored in the array .

  • The rendering process is to open a scene and then draw objects

    1. Drawing an object does not immediately transfer the vertex information of the object from the cpu to the gpu to call drawcall to draw
    2. Instead, it will first multiply the world matrix on the CPU to calculate the vertex position of the object in the world space, as well as other vertex information
    3. Then store it in the previously opened structure array, and then advance to the corresponding variable .
    4. Perform this operation every time an object is drawn, and then end a scene, or the number of vertices stored in the CPU exceeds the size of the structure array
    5. Then execute the drawcall operation
  • According to these two variables (the base position and the position of the last vertex), the vertex information of the corresponding size will be passed (glBufferSubData function)

    Pass from CPU to GPU, then OpenGL draws

Guess you like

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