2D Renderer Transforms and 2D Renderer Textures
在2D renderer 中,我们渲染的图元基本上全是矩形,加载纹理时,也是将对应的纹理贴到一个矩形内,本节就是实现了纹理在 2D renderer 中的加载以及进行了 shader 中 uniform 的设置从而控制图形的变换操作。
由于我们之前没有给 shader.cpp 中添加设置 uniform 的接口,之前对 uniform 的设置是通过强制转换为 OpenGLShader 指针之后再进行的设置:
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));
所以在 shader 中添加对应的接口:
virtual void SetInt(const std::string& name, int value) = 0;
virtual void SetFloat3(const std::string& name, const glm::vec3& value) = 0;
virtual void SetFloat4(const std::string& name, const glm::vec4& value) = 0;
virtual void SetMat4(const std::string& name, const glm::mat4& value) = 0;
在 OpenGLShader 中实现:
void OpenGLShader::SetInt(const std::string& name, int value)
{
UploadUniformInt(name, value);
}
void OpenGLShader::SetFloat3(const std::string& name, const glm::vec3& value)
{
UploadUniformFloat3(name, value);
}
void OpenGLShader::SetFloat4(const std::string& name, const glm::vec4& value)
{
UploadUniformFloat4(name, value);
}
void OpenGLShader::SetMat4(const std::string& name, const glm::mat4& value)
{
UploadUniformMat4(name, value);
}
然后之前用转换之后的指针进行设置 uniform 的代码可以换掉了:(这里添加了一个 Texture shader 用于 texture 加载)
s_Data->FlatColorShader->Bind();
s_Data->FlatColorShader->SetMat4("u_ViewProjection", camera.GetViewProjectionMatrix());
s_Data->TextureShader->Bind();
s_Data->TextureShader->SetMat4("u_ViewProjection", camera.GetViewProjectionMatrix());
DrawQuad
函数中的也可以替换掉了,并且添加了 transform:
void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color)
{
s_Data->FlatColorShader->Bind();
s_Data->FlatColorShader->SetFloat4("u_Color", color);
glm::mat4 transform = glm::translate(glm::mat4(1.0f), position) * glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f });
s_Data->FlatColorShader->SetMat4("u_Transform", transform);
s_Data->QuadVertexArray->Bind();
RenderCommand::DrawIndexed(s_Data->QuadVertexArray);
}
然后我们添加了用于绘制 texture 的 DrawQuad 函数:
void Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const Ref<Texture2D>& texture)
{
DrawQuad({ position.x, position.y, 0.0f }, size, texture);
}
void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref<Texture2D>& texture)
{
s_Data->TextureShader->Bind();
glm::mat4 transform = 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", transform);
texture->Bind();
s_Data->QuadVertexArray->Bind();
RenderCommand::DrawIndexed(s_Data->QuadVertexArray);
}
然后进行测试,首先创建成员变量 m_CheckerboardTexture ,然后在 SandBox::OnAttach 函数中进行加载:
m_CheckerboardTexture = Hazel::Texture2D::Create("assets/textures/Checkerboard.png");
添加纹理坐标,然后添加布局和进行 texture 绑定:
float squareVertices[5 * 4] = {
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f
};
squareVB->SetLayout({
{ ShaderDataType::Float3, "a_Position" },
{ ShaderDataType::Float2, "a_TexCoord" }
});
s_Data->TextureShader = Shader::Create("assets/shaders/Texture.glsl");
s_Data->TextureShader->Bind();
s_Data->TextureShader->SetInt("u_Texture", 0);
绘制了三个矩形进行测试,其中一个使用纹理:
Hazel::Renderer2D::BeginScene(m_CameraController.GetCamera());
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);
Hazel::Renderer2D::EndScene();
然后为了让 texture 显示在最底层,我们设置了其 z轴坐标为 -0.1,为了使设置生效,需要打开 OpenGL 的深度测试:
//OpenGLRenderAPI::Init()
glEnable(GL_DEPTH_TEST);
之后运行,正常显示结果: