Hazel game engine (062) batch rendering plus texture

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

foreword

  • Review texture sampling personal understanding.

    1. Load the texture resource, set the buffer m_RendererID opened by this texture resource to be bound to texture slot 0
    2. The texture sampled by glsl is sampled on texture slot 0, and texture slot 0 points to the texture resource in step 1, thus completing the sampling of the loaded texture.
  • OpenGL texture slots

    OpenGL limits how many texture slots a drawcall can use, usually 32

    But if you want to use more than 32 and 40 textures, you can:

    • Divide into two times, the first drawcall 32, then clear and reload the texture and then drawcall
    • This one is harder by getting around the GPU limit of 32 textures.
    • Use texture sets, texture altas

    This section is a drawcall that uses a fixed 32 texture slots.

general flow

  1. First upload a sample array with a default size of 32 for this shader in advance

    u_Textures[i] = j, where i = j, u_Textures[1] = 1 indicates that the fragment shader samples the texture on texture slot No. 1

    You don't need to care whether the texture buffer ID on texture slot 1 is equal to 1 or not.

  2. Load a texture to get a texture object, and save the texture object with an array

  3. When drawing quad graphics with texture , determine whether there is this texture object in the array

    If there is, take out the i subscript

    If not, add it to the end of the existing texture in the array, and record the subscript i

  4. Set the texture unit of the current vertex sampling to i , and then pass the texture slot number i from the vertex stage to the fragment shader stage

  5. Before Drawcall, the TextureSlots array stores the loaded textures and binds them to the corresponding texture slots in order

  6. During Drawcall, on the fragment shader, read the texture on the sampling corresponding to the texture slot number i

code flow

  • Remember the data structure first

    • std::array<Ref, MaxTextureSlots> TextureSlots;

      It is an array of size 32. The elements of the array are texture object pointers, which are used to store the loaded texture objects.

    • int32_t samplers[s_Data.MaxTextureSlots];

      It is an array of size 32, and the elements of the array are int values, which are used to upload to glsl

  1. First upload a sample array with a default size of 32 for this shader in advance, u_Textures[i] = j, where i = j, u_Textures[1] = 1 means the texture on the sampling texture slot No. 1

    // 纹理的shader
    s_Data.TextureShader = Shader::Create("assets/shaders/Texture.glsl");
    
    int32_t samplers[s_Data.MaxTextureSlots];
    for (uint32_t i = 0; i < s_Data.MaxTextureSlots; i++) {
          
          
    samplers[i] = i;
    }
    s_Data.TextureShader->Bind();// 上传数据前要先绑定shader
    // 为TextureShader上传一个默认的大小为32的采样数组,u_Textures[i] = j,其中i = j,u_Textures[1] = 1表示采样纹理槽1号上的纹理
    s_Data.TextureShader->SetIntArray("u_Textures", samplers, s_Data.MaxTextureSlots);
    
  2. Load a texture to get a texture object, and save the texture object with an array

    // 白色纹理
    // 创建一个白色Texture
    s_Data.WhiteTexture = Texture2D::Create(1, 1);
    uint32_t whiteTextureData = 0xffffffff;
    s_Data.WhiteTexture->SetData(&whiteTextureData, sizeof(uint32_t));
    
    // 0号纹理槽对应白色纹理缓冲区
    s_Data.TextureSlots[0] = s_Data.WhiteTexture;
    
  3. When drawing quad graphics, judge whether the TextureSlots array has this texture, take out the subscript i, if not, add it to the end of the existing texture in the array, and record the subscript i

    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++;// 记得++
    }
    // 设置当前顶点采样的纹理单元是 **i**
    
  4. Set the texture unit of the current vertex sampling in the vertex data array to i , and then pass the texture slot number i to the fragment stage in step 6

    // quad的左下角为起点
    s_Data.QuadVertexBufferPtr->Position = position;
    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++;
    

    glsl related

    s_Data.QuadVertexBuffer->SetLayout({
          
          
    {
          
          Hazel::ShaderDataType::Float3, "a_Position"},
    {
          
          Hazel::ShaderDataType::Float4, "a_Color"},
    {
          
          Hazel::ShaderDataType::Float2, "a_TexCoord"},
    {
          
          Hazel::ShaderDataType::Float, "a_TexIndex"},
    {
          
          Hazel::ShaderDataType::Float, "a_TilingFactor"}
    });// 顶点布局
    
    #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;
    layout(location = 3) in float a_TexIndex;
    layout(location = 4) in float a_TilingFactor;
    
  5. Before Drawcall, the TextureSlots array stores the loaded textures and binds them to the corresponding texture slots in order

    In this way, the texture slot number i of the current vertex sampling is set in steps 3 and 4, which is the texture number i on the TextureSlots array

    void Renderer2D::Flush()
    {
          
          
        // 对应i的texture绑定到i号纹理槽
        for (uint32_t i = 0; i < s_Data.TextureSlotIndex; i++) {
          
          
            s_Data.TextureSlots[i]->Bind(i);
        }
        RenderCommand::DrawIndexed(s_Data.QuadVertexArray, s_Data.QuadIndexCount);
    }
    
  6. During Drawcall, on the fragment shader, read the texture on the sampling corresponding to the texture slot number i

    #type fragment
    #version 330 core
    
    layout(location = 0) out vec4 color;
    
    in vec4 v_Color;
    in vec2 v_TexCoord;
    in float v_TexIndex;// 从顶点着色器传入,在cpp代码的drawquad函数中设置
    in float v_TilingFactor;
    // 纹理槽号数组u_Textures[i] = j, 其中i = j,u_Textures[1] = 1表示采样纹理槽1号上的纹理
    uniform sampler2D u_Textures[32]; 
    
    void main() {
        // 采样纹理槽v_TexIndex号上的纹理
    	color = texture(u_Textures[int(v_TexIndex)], v_TexCoord * v_TilingFactor) * v_Color;	
    	//color = v_Color;
    }
    

Watch out for bugs

  • Bind before uploading Shader data

    s_Data.TextureShader->Bind();// 上传数据前要先绑定shader
    s_Data.TextureShader->SetIntArray("u_Textures", samplers, s_Data.MaxTextureSlots);
    
  • Do not mix u_color and v_color in glsl

  • Remove extraneous variables on glsl

question

Why does Texture overload the == operator

Texture2D
virtual bool operator==(const Texture2D& other) const = 0;
OpenGLShader
virtual bool operator==(const Texture2D& other) const override
{
    
    
    return m_RendererID == ((OpenGLTexture2D&)other).m_RendererID;
}
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++)
    {
    
    
        // 当前纹理,如果已经存储在纹理槽,就直接读取
        // 使用了 == 运算符,对比m_RendereID是否相同
        // TextureSlots数组的元素是Texture2D父类指针,而texture也是Texture2D父类指针
        if (*s_Data.TextureSlots[i].get() == *texture.get()) {
    
    
            textureIndex = (float)i;
            break;
        }
    }
  1. The elements of the TextureSlots array are Texture2D parent class pointers

  2. And texture is also a Texture2D parent class pointer

  3. But m_RendererID is a private variable of the OpenGLTexture2D subclass , and the parent class Texture2D has no m_RendererID attribute

  4. So cannot write *s_Data.TextureSlots[i].get().m_RendererID == *texture.get().m_RendererID

    Please add a picture description

So it can only be compared by overloading the == operator, then converting to a subclass object, and then accessing private member properties

Please add a picture description

result

Please add a picture description

full code

Texture.glsl

// 纹理的glsl
#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;
layout(location = 3) in float a_TexIndex;
layout(location = 4) in float a_TilingFactor;

uniform mat4 u_ViewProjection;

out vec4 v_Color;
out vec2 v_TexCoord;
out float v_TexIndex;
out float v_TilingFactor;

void main() {
	v_Color = a_Color;
	v_TexCoord = a_TexCoord;
	v_TexIndex = a_TexIndex;
	v_TilingFactor = a_TilingFactor;
	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;
in float v_TexIndex;
in float v_TilingFactor;

uniform sampler2D u_Textures[32]; 

void main() {
	 color = texture(u_Textures[int(v_TexIndex)], v_TexCoord * v_TilingFactor) * v_Color;
	//color = v_Color;
}

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;
		float TexIndex;
		float TilingFactor;
	};
	struct Renderer2DData {
    
    
		const uint32_t MaxQuads = 10000;
		const uint32_t MaxVertices = MaxQuads * 4;
		const uint32_t MaxIndices = MaxQuads * 6;
		static const uint32_t MaxTextureSlots = 32; // 最大的纹理槽数

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

		uint32_t QuadIndexCount = 0;
		QuadVertex* QuadVertexBufferBase = nullptr;
		QuadVertex* QuadVertexBufferPtr = nullptr;

		std::array<Ref<Texture2D>, MaxTextureSlots> TextureSlots;
		uint32_t TextureSlotIndex = 1;// 0 号给白色纹理

	};
	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"},
			{
    
    Hazel::ShaderDataType::Float, "a_TexIndex"},
			{
    
    Hazel::ShaderDataType::Float, "a_TilingFactor"}
			});

		// 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;

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

		// 0号给白色纹理
		s_Data.TextureSlots[0] = s_Data.WhiteTexture;

		// 纹理的shader
		s_Data.TextureShader = Shader::Create("assets/shaders/Texture.glsl");

		int32_t samplers[s_Data.MaxTextureSlots];
		for (uint32_t i = 0; i < s_Data.MaxTextureSlots; i++) {
    
    
			samplers[i] = i;
		}
		s_Data.TextureShader->Bind();// 上传数据前要先绑定shader
		// 为TextureShader上传一个默认的大小为32的采样数组,u_Textures[i] = j,其中i = j,u_Textures[1] = 1表示采样纹理槽1号上的纹理
		s_Data.TextureShader->SetIntArray("u_Textures", samplers, s_Data.MaxTextureSlots);
	}

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

		// 初始化
		s_Data.QuadIndexCount = 0;
		s_Data.QuadVertexBufferPtr = s_Data.QuadVertexBufferBase;

		s_Data.TextureSlotIndex = 1;
	}

	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()
	{
    
    
		// 对应i的texture绑定到i号纹理槽
		for (uint32_t i = 0; i < s_Data.TextureSlotIndex; i++) {
    
    
			s_Data.TextureSlots[i]->Bind(i);
		}
		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();

		const float textureIndex = 0.0f; // 白色纹理
		const float tilingFactor = 1.0f;

		// quad的左下角为起点
		s_Data.QuadVertexBufferPtr->Position = position;
		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 = {
    
     position.x + size.x, position.y, 0.0f };
		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 = {
    
     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->TexIndex = textureIndex;
		s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor;
		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->TexIndex = textureIndex;
		s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor;
		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();

		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++;// 记得++
		}
		// quad的左下角为起点
		s_Data.QuadVertexBufferPtr->Position = position;
		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 = {
    
     position.x + size.x, position.y, 0.0f };
		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 = {
    
     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->TexIndex = textureIndex;
		s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor;
		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->TexIndex = textureIndex;
		s_Data.QuadVertexBufferPtr->TilingFactor = tilingFactor;
		s_Data.QuadVertexBufferPtr++;

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

#if OLD_PATH
		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);
#endif // 0
	}
	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/131882951