游戏引擎从零开始(37)-Batch Rendering(3)

批渲染中的旋转处理

这章我们继续完善批渲染,支持旋转处理。

回顾下通用的顶点着色器的代码:

c++ 复制代码
void main()
{
	v_Color = a_Color;
	v_TexCoord = a_TexCoord;
	v_TexIndex = a_TexIndex;
	gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0);
}

一个顶点的坐标计算依赖"投影矩阵(u_ViewProjection)"、"移动变换(u_Transform)"、"原始坐标(a_Position)",其中u_Transform是由程序中传进来的通用变量,一个完整的网格有一个u_Transform,多个网格就对应多个u_Transform,

如果要实现多个网格批渲染,就需要类似color一样,将u_Transform作为顶点属性传进来,以实现每个顶点的u_Transform都不一样。

另一个方法是,在shader外面将transform提前乘到position上,即传到shader中的顶点已经计算过旋转、缩放、位移了。shader修改为:

c++ 复制代码
void main()
{
	v_Color = a_Color;
	v_TexCoord = a_TexCoord;
	v_TexIndex = a_TexIndex;
	v_TilingFactor = a_TilingFactor;
	// gl_Position = u_ViewProjection * u_Transform * vec4(a_Position, 1.0);
	gl_Position = u_ViewProjection * vec4(a_Position, 1.0);
}

最终的实现效果如下,demo中增加旋转的矩形:

代码实现

整体思路是,在draw函数中,将旋转乘到position上

Sandbox/Hazel/src/Hazel/Renderer/Renderer2D.cpp

c++ 复制代码
// 1. 增加单位矩阵的顶点

struct Renderer2DData{
....
  std::array<Ref<Texture2D>, MaxTexturesSlots> TextureSlots;
  uint32_t TextureSlotIndex = 1; // 0 = white texture

  glm::vec4 QuadVertexPositions[4]; // 矩形的四个顶点
}

// 2. 初始化单位矩阵的顶点
void Renderer2D::Init() {
....
  // Set all texture slots to 0
  // 安全起见,将数组中的每个值都初始化成一个默认的纹理,即单像素纹理
  for (int i = 0; i < s_Data->MaxTexturesSlots; i++) {
      s_Data->TextureSlots[i] = s_Data->WhiteTexture;
  }

  // 初始化单位矩阵的顶点坐标
  s_Data->QuadVertexPositions[0] = {-0.5f, -0.5f, 0.0f, 1.0f};
  s_Data->QuadVertexPositions[1] = {0.5f, -0.5f, 0.0f, 1.0f};
  s_Data->QuadVertexPositions[2] = {0.5f, 0.5f, 0.0f, 1.0f};
  s_Data->QuadVertexPositions[3] = {-0.5f, 0.5f, 0.0f, 1.0f};
}

// 3. DrawQuad函数中增加旋转处理

void Renderer2D::DrawQuad(const glm::vec3 &position, const glm::vec2 &size, float rotation,
                                 const glm::vec4 &color) {
    HZ_PROFILE_FUNCTION();
    const float texIndex = 0.0f; // white Texture
    const float tilingFactor = 1.0f;

    glm::mat4 transform = 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});


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


    s_Data->QuadVertexBufferPtr->Position = transform * s_Data->QuadVertexPositions[0];
    ...
    
    s_Data->QuadVertexBufferPtr->Position = transform * s_Data->QuadVertexPositions[1];
    
    ...
    s_Data->QuadVertexBufferPtr->Position = transform * s_Data->QuadVertexPositions[2];
    
    ...
    s_Data->QuadVertexBufferPtr->Position = transform * s_Data->QuadVertexPositions[3];

}

...

一共有4个重载的Renderer2D::DrawQuad函数,都需要改进,将transform提前计算好,乘到position上。此处仅说明实现思路,完整代码参考文末github地址

demo中增加旋转的矩阵,此处我们根据update的时间,动态的增加旋转角度

Sandbox/src/Sandbox2D.cpp

c++ 复制代码
{
    HZ_PROFILE_SCOPE("Renderer Draw");

    static float rotation = 0.f;
    rotation += ts * 50.0f;

    Hazel::Renderer2D::BeginScene(m_CameraController.GetCamera());

    // 旋转45°
    Hazel::Renderer2D::DrawQuad({1.0f, 0.0f}, {0.8f, 0.8f}, -45, {0.8f, 0.2f, 0.3f, 1.0f});

    // 静态矩形
    Hazel::Renderer2D::DrawQuad({-1.0f, 0.0f}, {0.8f, 0.8f}, {0.8f, 0.2f, 0.3f, 1.0f});
    Hazel::Renderer2D::DrawQuad({0.5f, -0.5f}, {0.5f, 0.75f}, {0.2f, 0.3f, 0.8f, 1.0f});
    Hazel::Renderer2D::DrawQuad({0.0f, 0.0f, -0.1f}, {10.0f, 10.0f}, m_CheckerboardTexture, 10.0f);

    // 持续旋转45°
    Hazel::Renderer2D::DrawQuad({1.f, 0.5f, 0.1f}, {0.8f, 0.8f}, rotation, m_CoverTexture, 1.0f);

    Hazel::Renderer2D::EndScene();

}

完整代码 & 总结

完整代码

github.com/summer-go/H...

总结

批渲染的核心,就是将所有要绘制的数据尽量统一起来,去异求同,将不同的地方提前处理好或者在shader中按参数动态计算,以达到使用同一个shader,不切换状态,一次绘制上屏。

最近工作有点累,加上流感盛行,娃老生病,有点干不动了。加油💪🏻

相关推荐
刘好念5 天前
[OpenGL]使用OpenGL实现硬阴影效果
c++·计算机图形学·opengl
闲暇部落5 天前
Android OpenGL ES详解——纹理:纹理过滤GL_NEAREST和GL_LINEAR的区别
opengl·texture·linear·纹理过滤·nearest·邻近过滤·线性过滤
凌云行者7 天前
OpenGL入门005——使用Shader类管理着色器
c++·cmake·opengl
凌云行者7 天前
OpenGL入门006——着色器在纹理混合中的应用
c++·cmake·opengl
凌云行者9 天前
OpenGL入门004——使用EBO绘制矩形
c++·cmake·opengl
Thomas_YXQ10 天前
Unity3D中管理Shader效果详解
开发语言·游戏·unity·unity3d·游戏开发
闲暇部落10 天前
Android OpenGL ES详解——模板Stencil
android·kotlin·opengl·模板测试·stencil·模板缓冲·物体轮廓
凌云行者12 天前
OpenGL入门003——使用Factory设计模式简化渲染流程
c++·cmake·opengl
凌云行者12 天前
OpenGL入门002——顶点着色器和片段着色器
c++·cmake·opengl
Ljw...13 天前
C++游戏开发
c++·c·游戏开发