跟着cherno手搓游戏引擎【29】Batch简单合批

news2024/11/23 12:48:31

思路:

CPU和GPU都开辟同样大小的一大块内存(为了存储顶点信息)

索引在程序运行时生成对应规则后绑定到索引缓冲中

动态生成顶点信息(现在改成Drawquad只是确定图形顶点的位置)

然后在Endscene,将CPU的动态生成的顶点数据上传给GPU,然后再绘制出来

所以,就是根据所绘制的物体,动态生成索引缓冲区,然后根据索引缓冲区一次性绘制多个物体

实现:

Renderer2D.h:

#pragma once
#include "OrthographicCamera.h"
#include"Texture.h"
namespace YOTO {
	class Renderer2D
	{
	public:
		//为什么渲染器是静态的:
		static void Init();
		static void ShutDown();
		static void BeginScene(const OrthographicCamera& camera);
		static void EndScene();
		static void Flush();

		static void DrawQuad(const glm::vec2& position, const glm::vec2& size ,const glm::vec4& color);
		static void DrawQuad(const glm::vec3& position, const glm::vec2& size ,const glm::vec4& color);
		static void DrawQuad(const glm::vec2& position, const glm::vec2& size ,const Ref<Texture2D> texture,float tilingFactor=1.0f,const glm::vec4& tintColor=glm::vec4(1.0f));
		static void DrawQuad(const glm::vec3& position, const glm::vec2& size ,const Ref<Texture2D> texture,float tilingFactor=1.0f,const glm::vec4& tintColor=glm::vec4(1.0f));

		static void DrawRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation,const glm::vec4& color);
		static void DrawRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation,const glm::vec4& color);
		static void DrawRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation,const Ref<Texture2D> texture, float tilingFactor = 1.0f,  const glm::vec4& tintColor = glm::vec4(1.0f));
		static void DrawRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation,const Ref<Texture2D> texture, float tilingFactor = 1.0f, const glm::vec4& tintColor = glm::vec4(1.0f));
	};
}


Renderer2D.cpp:

#include "ytpch.h"
#include "Renderer2D.h"
#include"VertexArray.h"
#include"Shader.h"
//#include "Platform/OpenGL/OpenGLShader.h"
#include <glm/gtc/matrix_transform.hpp>
#include "RenderCommand.h"
namespace YOTO {
	/// <summary>
	/// 为什么QuadVertex的指针可以作为void*data传入glBufferSubData:
	/// SetLayout配置的就是这三个的顺序,因为glm内部用float实现
	/// 相当于前三个float是Position,之后四个float组成的Color,
	/// 最后是两个float组成的TexCoord
	/// </summary>
	struct QuadVertex {
		glm::vec3 Position;
		glm::vec4 Color;
		glm::vec2 TexCoord;
		//,纹理Id,
	};
	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> FlatColorShader;
		//Shader
		Ref<Shader> TextureShader;
		//纹理
		Ref<Texture2D> WhiteTexture;
		//记录索引
		uint32_t QuadIndexCount =0;

		QuadVertex* QuadVertexBufferBase=nullptr;
		QuadVertex* QuadVertexBufferPtr= nullptr;
	};
	//CPU开辟的大内存
	static Renderer2DData s_Data;


	void Renderer2D::Init()
	{
		YT_PROFILE_FUNCTION();
		//---------------------顶点数组--------------------------
		//创建顶点数组
		s_Data.QuadVertexArray = VertexArray::Create();
		// 创建顶点缓冲区,先在GPU开辟一块s_Data.MaxVertices * sizeof(QuadVertex)大小的内存
		// 与cpu对应大,是为了传输顶点数据
		//---------------------顶点缓冲区--------------------------
		s_Data.QuadVertexBuffer =VertexBuffer::Create(s_Data.MaxVertices*sizeof(QuadVertex));
		s_Data.QuadVertexBuffer->SetLayout({
				{ShaderDataType::Float3,"a_Position"},
				{ShaderDataType::Float4,"a_Color"},
				{ShaderDataType::Float2,"a_TexCoord"}
			});
		//顶点数组添加顶点缓冲区,并且在这个缓冲区中设置布局
		s_Data.QuadVertexArray->AddVertexBuffer(s_Data.QuadVertexBuffer);


		// 在CPU开辟存储s_Data.MaxVertices个的QuadVertex的内存
		s_Data.QuadVertexBufferBase = new QuadVertex[s_Data.MaxVertices];
		
		//---------------------索引缓冲区--------------------------
		//开辟一块索引缓冲区
		uint32_t* quadIndices = new uint32_t[s_Data.MaxIndices];
		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> quardIB;
		quardIB =IndexBuffer::Create(quadIndices, s_Data.MaxIndices);
		s_Data.QuadVertexArray->AddIndexBuffer(quardIB);
		delete[] quadIndices;	// cpu上传到gpu上了可以删除cpu的索引数据块了

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

		//---------------------着色器--------------------------
		//加载shader,并传入shader参数
		s_Data.TextureShader= Shader::Create("assets/shaders/Texture.glsl");
		s_Data.TextureShader->Bind();
		s_Data.TextureShader->SetInt("u_Texture", 0);



	}
	void Renderer2D::ShutDown()
	{
		YT_PROFILE_FUNCTION();
		//delete s_Data;
	}
	void Renderer2D::BeginScene(const OrthographicCamera& camera)
	{

		YT_PROFILE_FUNCTION();
		s_Data.TextureShader->Bind();
		s_Data.TextureShader->SetMat4("u_ViewProjection", camera.GetViewProjectionMatrix());
		// 相当于初始化此帧要绘制的索引数量,上传的顶点数据
		s_Data.QuadIndexCount = 0;
		//指针指向首部
		s_Data.QuadVertexBufferPtr = s_Data.QuadVertexBufferBase;
	}
	void Renderer2D::EndScene()
	{
		YT_PROFILE_FUNCTION();
		// 计算当前绘制需要多少个顶点数据,注意这里是8!!!!!!
		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 Renderer2D::DrawQuad(const glm::vec2& position, const glm::vec2& size, const glm::vec4& color)
	{
		DrawQuad({ position.x,position.y,0.0f }, size, color);
	}
	void Renderer2D::DrawQuad(const glm::vec3& position, const glm::vec2& size, const glm::vec4& color)
	{
		YT_PROFILE_FUNCTION();
		//s_Data.FlatColorShader->Bind();
		//s_Data.FlatColorShader->SetFloat4("u_Color", color);
		//s_Data.TextureShader->Bind();

		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;
		/*s_Data.TextureShader->SetFloat4("u_Color", color);
		s_Data.TextureShader->SetFloat("m_TilingFactor", 1.0f);
		s_Data.WhiteTexture->Bind();*/

		//glm::mat4 transform = glm::translate(glm::mat4(1.0f), position) /**rotation*/ * glm::scale(glm::mat4(1.0f), {size.x,size.y,1.0f});
		//s_Data.TextureShader->SetMat4("u_Transform", transform);
		//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)
	{
		YT_PROFILE_FUNCTION();
		//s_Data.TextureShader->Bind();
		s_Data.TextureShader->SetFloat4("u_Color", tintColor);
		s_Data.TextureShader->SetFloat("m_TilingFactor",tilingFactor);
		texture->Bind();


		glm::mat4 transform = glm::translate(glm::mat4(1.0f), position) /**rotation*/ * glm::scale(glm::mat4(1.0f), { size.x,size.y,1.0f });
		s_Data.TextureShader->SetMat4("u_Transform", transform);

		s_Data.QuadVertexArray->Bind();
		RenderCommand::DrawIndexed(s_Data.QuadVertexArray);
		
	}
	void Renderer2D::DrawRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const glm::vec4& color)
	{
		DrawRotatedQuad({ position.x,position.y,0.0f }, size, rotation,color);
	}
	void Renderer2D::DrawRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const glm::vec4& color)
	{
		YT_PROFILE_FUNCTION();

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

		glm::mat4 transform = 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", transform);
		s_Data.QuadVertexArray->Bind();
		RenderCommand::DrawIndexed(s_Data.QuadVertexArray);

	}
	void Renderer2D::DrawRotatedQuad(const glm::vec2& position, const glm::vec2& size, float rotation, const Ref<Texture2D> texture, float tilingFactor, const glm::vec4& tintColor)
	{
		DrawRotatedQuad({ position.x,position.y,0.0f }, size, rotation, texture, tilingFactor, tintColor);
	}
	void Renderer2D::DrawRotatedQuad(const glm::vec3& position, const glm::vec2& size, float rotation, const Ref<Texture2D> texture, float tilingFactor, const glm::vec4& tintColor)
	{
		YT_PROFILE_FUNCTION();
		//s_Data.TextureShader->Bind();
		s_Data.TextureShader->SetFloat4("u_Color", tintColor);
		s_Data.TextureShader->SetFloat("m_TilingFactor", tilingFactor);
		texture->Bind();


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

		s_Data.QuadVertexArray->Bind();
		RenderCommand::DrawIndexed(s_Data.QuadVertexArray);
	}
}

Buffer.h:添加SetData和Create方法:

#pragma once
namespace YOTO {
	enum class ShaderDataType{
	None=0,
	Float,Float2,Float3,Float4,
	Mat3,Mat4,
	Int,Int2,Int3,Int4,
	Bool,
	};
	static uint32_t  ShaderDataTypeSize(ShaderDataType type) {
		switch (type)
		{
		case YOTO::ShaderDataType::Float:
			return 4;
			break;
		case YOTO::ShaderDataType::Float2:
			return 4*2;
			break;
		case YOTO::ShaderDataType::Float3:
			return 4*3;
			break;
		case YOTO::ShaderDataType::Float4:
			return 4*4;
			break;
		case YOTO::ShaderDataType::Mat3:
			return 4*3*3;
			break;
		case YOTO::ShaderDataType::Mat4:
			return 4*4*4;
			break;
		case YOTO::ShaderDataType::Int:
			return 4;
			break;
		case YOTO::ShaderDataType::Int2:
			return 4*2;
			break;
		case YOTO::ShaderDataType::Int3:
			return 4*3;
			break;
		case YOTO::ShaderDataType::Int4:
			return 4*4;
			break;
		case YOTO::ShaderDataType::Bool:
			return 1;
			break;
		}
		YT_CORE_ASSERT(false, "未知的ShaderDataType!");
		return 0;
	}
	struct BufferElement {
		std::string Name;
		ShaderDataType Type;
		uint32_t Size;
		uint32_t Offset;
		bool Normalized;
		BufferElement(){}
		BufferElement(ShaderDataType type, const std::string& name,bool normalized=false)
			:Name(name), Type(type), Size(ShaderDataTypeSize(type)), Offset(0), Normalized(normalized){}
		uint32_t GetComponentCount() const{
			switch (Type)
			{
			case YOTO::ShaderDataType::Float:
				return 1;
				break;
			case YOTO::ShaderDataType::Float2:
				return 2;
				break;
			case YOTO::ShaderDataType::Float3:
				return 3;
				break;
			case YOTO::ShaderDataType::Float4:
				return 4;
				break;
			case YOTO::ShaderDataType::Mat3:
				return 3*3;
				break;
			case YOTO::ShaderDataType::Mat4:
				return 4*4;
				break;
			case YOTO::ShaderDataType::Int:
				return 1;
				break;
			case YOTO::ShaderDataType::Int2:
				return 2;
				break;
			case YOTO::ShaderDataType::Int3:
				return 3;
				break;
			case YOTO::ShaderDataType::Int4:
				return 4;
				break;
			case YOTO::ShaderDataType::Bool:
				return 1;
				break;
			default:
				break;
			}
			YT_CORE_ASSERT(false, "未知的ShaderDataType!");
			return 0;
		}
	};
	class BufferLayout {
	public:
		BufferLayout(){}
		BufferLayout(const std::initializer_list<BufferElement>elements)
			:m_Elements(elements) 
		{
			CalculateOffsetAndStride();
		} 
		inline uint32_t GetStride()const { return m_Stride; }
		inline const std::vector<BufferElement>& GetElements()const {
			return m_Elements;
		}
		std::vector<BufferElement>::iterator begin() { return m_Elements.begin(); }
		std::vector<BufferElement>::iterator end() { return m_Elements.end(); }
		std::vector<BufferElement>::const_iterator begin() const { return m_Elements.begin(); }
		std::vector<BufferElement>::const_iterator end() const { return m_Elements.end(); }
	private:
		void CalculateOffsetAndStride() {
			uint32_t offset = 0;
			m_Stride = 0;
			for (auto& element : m_Elements) {
				element.Offset = offset;
				offset += element.Size;
				m_Stride += element.Size;
			}
		}
	private:
		std::vector<BufferElement> m_Elements;
		uint32_t m_Stride = 0;
	};
	class VertexBuffer {
	public:
		virtual~VertexBuffer() {}

		virtual void Bind() const = 0;
		virtual void UnBind() const = 0;

		virtual void SetData(const void* data, uint32_t size) = 0;

		virtual void SetLayout(const BufferLayout& layout) = 0;
		virtual const BufferLayout& GetLayout()const = 0;
		

		static  Ref<VertexBuffer> Create(float* vertices, uint32_t size);
		static  Ref<VertexBuffer> Create(uint32_t size);
	};
	/// <summary>
	/// 目前索引仅支持32位的索引缓冲区
	/// </summary>
	class IndexBuffer {
	public:
		virtual~IndexBuffer(){}
		virtual void Bind() const = 0;
		virtual void UnBind() const = 0;
		virtual uint32_t GetCount() const = 0;
		static  Ref<IndexBuffer> Create(uint32_t* indices, uint32_t count);

	};
}

Buffer.cpp:

#include"ytpch.h"
#include"Buffer.h"
#include "Renderer.h"

#include "Platform/OpenGL/OpenGLBuffer.h"

namespace YOTO {

	Ref<VertexBuffer> VertexBuffer::Create(uint32_t size)
	{
		switch (Renderer::GetAPI())
		{
		case RendererAPI::API::None:
			YT_CORE_ASSERT(false, "Buffer:API为None不支持");
			return nullptr;
		case RendererAPI::API::OpenGL:
			return std::make_shared<OpenGLVertexBuffer>(size);
		}
		YT_CORE_ASSERT(false, "Buffer:未知API");
		return nullptr;
	}
	Ref<VertexBuffer> VertexBuffer::Create(float* vertices, uint32_t size)
	{
		switch (Renderer::GetAPI())
		{
		case RendererAPI::API::None:
			YT_CORE_ASSERT(false,"Buffer:API为None不支持");
			return nullptr;
		case RendererAPI::API::OpenGL:
			return std::make_shared<OpenGLVertexBuffer>(vertices,size);
		}
		YT_CORE_ASSERT(false,"Buffer:未知API");
		return nullptr;
	}

	Ref<IndexBuffer> IndexBuffer::Create(uint32_t* indices, uint32_t count)
	{
		switch (Renderer::GetAPI())
		{
		case RendererAPI::API::None:
			YT_CORE_ASSERT(false, "Buffer:API为None不支持");
			return nullptr;
		case RendererAPI::API::OpenGL:
			return std::make_shared < OpenGLIndexBuffer>(indices, count);
		}
		YT_CORE_ASSERT(false, "Buffer:未知API");
		return nullptr;
	}

}

OpenGLBuffer.cpp: 实现继承自Buffer的方法

#include"ytpch.h"
#include"OpenGLBuffer.h"
#include <glad/glad.h>
namespace YOTO {

	
	// VertexBuffer 
	

	OpenGLVertexBuffer::OpenGLVertexBuffer(uint32_t size)
	{
		YT_PROFILE_FUNCTION();
		glCreateBuffers(1, &m_RendererID);
		glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
		glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_DYNAMIC_DRAW);
	}
	OpenGLVertexBuffer::OpenGLVertexBuffer(float* vertices, uint32_t size)
	{	 
		YT_PROFILE_FUNCTION();
		glCreateBuffers(1, &m_RendererID);
		glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
		glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
	}
	OpenGLVertexBuffer::~OpenGLVertexBuffer()
	{
		YT_PROFILE_FUNCTION();
		glDeleteBuffers(1, &m_RendererID);
	}
	void OpenGLVertexBuffer::Bind() const
	{
		YT_PROFILE_FUNCTION();
		glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
	}
	void OpenGLVertexBuffer::UnBind() const
	{
		glBindBuffer(GL_ARRAY_BUFFER, 0);
	}

	void OpenGLVertexBuffer::SetData(const void* data, uint32_t size)
	{
		glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
		// 用来更新一个已有缓冲区对象中的一部分数据,
		//data:一个指向新数据源的指针,将新的数据源拷贝到缓冲区对象中完成更新
		glBufferSubData(GL_ARRAY_BUFFER,0,size,data);
	}

	
	// IndexBuffer /
	
	OpenGLIndexBuffer::OpenGLIndexBuffer(uint32_t* indices, uint32_t count)
		:m_Count(count)
	{
		YT_PROFILE_FUNCTION();
		glCreateBuffers(1, &m_RendererID);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, count*sizeof(uint32_t), indices, GL_STATIC_DRAW);
	}
	OpenGLIndexBuffer::~OpenGLIndexBuffer()
	{
		YT_PROFILE_FUNCTION();
		glDeleteBuffers(1, &m_RendererID);
	}
	void OpenGLIndexBuffer::Bind() const
	{
		YT_PROFILE_FUNCTION();
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
	}
	void OpenGLIndexBuffer::UnBind() const
	{
		YT_PROFILE_FUNCTION();
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	}
}

RenderAPI.h:创建DrawIndexed方法根据索引绘制图像:

#pragma once
#include<glm/glm.hpp>
#include "VertexArray.h"
namespace YOTO {
	class RendererAPI
	{
	public:
		enum class API {
			None = 0,
			OpenGL = 1
		};
	public:
		virtual void Init() = 0;
		virtual void SetClearColor(const glm::vec4& color)=0;
		virtual void SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) = 0;
		virtual void Clear() = 0;
		virtual void DrawIndexed(const Ref<VertexArray>& vertexArray,uint32_t indexCount = 0)=0;

		inline static API GetAPI() { return s_API; }
	private:
		static API s_API;
	};
}


OpenGLRendererAPI.cpp: 

#include "ytpch.h"
#include "OpenGLRendererAPI.h"
#include <glad/glad.h>
namespace YOTO {
	void OpenGLRendererAPI::Init()
	{
		YT_PROFILE_FUNCTION();
		//启用混合
		glEnable(GL_BLEND);
		//设置混合函数
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
		//深度测试
		glEnable(GL_DEPTH_TEST);
	}
	void OpenGLRendererAPI::SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
	{
		glViewport(x, y, width, height);
	}
	void OpenGLRendererAPI::SetClearColor(const glm::vec4& color)
	{
		glClearColor(color.r, color.g, color.b, color.a);
	}
	void OpenGLRendererAPI::Clear()
	{
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	}
	void OpenGLRendererAPI::DrawIndexed(const Ref<VertexArray>& vertexArray, uint32_t indexCount)
	{
		uint32_t count = indexCount ? vertexArray->GetIndexBuffer()->GetCount() : indexCount;
		glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
		glBindTexture(GL_TEXTURE_2D, 0);
	}
}

RenderCommand.h: 对API的DrawIndexed封装:

#pragma once
#include"RendererAPI.h"
namespace YOTO {
	class RenderCommand
	{
	public:
		inline static void Init() {
			s_RendererAPI->Init();
		}
		inline static void SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
			s_RendererAPI->SetViewport(x,y,width,height);
		}

		inline static void SetClearColor(const glm::vec4& color) {
			s_RendererAPI->SetClearColor(color);
		}
		inline static void Clear() {
			s_RendererAPI->Clear();
		}
		inline static void DrawIndexed(const Ref<VertexArray>& vertexArray,uint32_t count=0) {
			s_RendererAPI->DrawIndexed(vertexArray, count);
		}
		
	private:
		static RendererAPI* s_RendererAPI;

	};

}

 调用:

Texture.glsl:先改下shader

#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;
}

Sandbox2D.cpp:

#include "Sandbox2D.h"
#include <imgui/imgui.h>
#include <glm/gtc/matrix_transform.hpp>
//#include <Platform/OpenGL/OpenGLShader.h>
#include <glm/gtc/type_ptr.hpp>
#include<vector>
#include<chrono>
template<typename Fn>
class Timer {
public:
	Timer(const char* name, Fn&&func)
		:m_Name(name),m_Func(func),m_Stopped(false)
	{
		m_StartTimepoint = std::chrono::high_resolution_clock::now();
	}
	~Timer() {
		if (!m_Stopped) {
			Stop();
		}
	}
	void Stop() {
		auto endTimepoint= std::chrono::high_resolution_clock::now();
		long long start = std::chrono::time_point_cast<std::chrono::microseconds>(m_StartTimepoint).time_since_epoch().count();
		long long end = std::chrono::time_point_cast<std::chrono::microseconds>(endTimepoint).time_since_epoch().count();
		m_Stopped = true;
		float duration = (end - start)*0.001f;
		m_Func({m_Name,duration});
		//std::cout << "Timer:"<< m_Name << "时差:" << duration << "ms" << std::endl;
	}
private:
	const char* m_Name;
	std::chrono::time_point<std::chrono::steady_clock>m_StartTimepoint;
	bool m_Stopped;
	Fn m_Func;
};
//未找到匹配的重载:auto的问题,改回原来的类型就好了
#define PROFILE_SCOPE(name) Timer timer##__LINE__(name,[&](ProfileResult profileResult) {m_ProfileResults.push_back(profileResult);})
Sandbox2D::Sandbox2D()
:Layer("Sandbox2D"), m_CameraController(1280.0f / 720.0f, true) 
{
}
void Sandbox2D::OnAttach()
{
	YT_PROFILE_FUNCTION();
	m_CheckerboardTexture = YOTO::Texture2D::Create("assets/textures/Checkerboard.png");

}
void Sandbox2D::OnDetach()
{
	YT_PROFILE_FUNCTION();
}

void Sandbox2D::OnUpdate(YOTO::Timestep ts)
{
	YT_PROFILE_FUNCTION();
		//update
		m_CameraController.OnUpdate(ts);
	
	
	{
		YT_PROFILE_SCOPE("Sandbox2D::Renderer Prep");
		//Render
		YOTO::RenderCommand::SetClearColor({ 0.2f, 0.2f, 0.2f, 1.0f });
		YOTO::RenderCommand::Clear();
	}
	
	{
		YT_PROFILE_SCOPE("Sandbox2D::Renderer Draw");
		YOTO::Renderer2D::BeginScene(m_CameraController.GetCamera());
		{
	/*		static glm::mat4 scale = glm::scale(glm::mat4(1.0f), glm::vec3(0.1f));
			glm::vec4  redColor(0.8f, 0.3f, 0.3f, 1.0f);
			glm::vec4  blueColor(0.2f, 0.3f, 0.8f, 1.0f);*/


			/*std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_FlatColorShader)->Bind();
			std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_FlatColorShader)->UploadUniformFloat4("u_Color", m_SquareColor);
			YOTO::Renderer::Submit(m_FlatColorShader, m_SquareVA, glm::scale(glm::mat4(1.0f), glm::vec3(1.5f)));*/

		//	YOTO::Renderer2D::DrawRotatedQuad({ -1.0f,0.0f }, { 0.8f,0.8f }, glm::radians(45.0f),{ 0.8f,0.2f,0.3f,1.0f });
			YOTO::Renderer2D::DrawQuad({ -1.0f,0.0f }, { 0.8f,0.8f }, { 0.8f,0.2f,0.3f,1.0f });
			YOTO::Renderer2D::DrawQuad({ 0.5f,-0.5f }, { 0.5f,0.75f }, { 0.2f,0.3f,0.8f,1.0f });
			//YOTO::Renderer2D::DrawQuad({ 0.0f,0.0f,-0.1f }, { 10.0f,10.0f }, m_CheckerboardTexture,10.0f,glm::vec4(1.0f,0.9f,0.9f,1.0f));
			YOTO::Renderer2D::EndScene();
		}
	}
	
}
void Sandbox2D::OnImGuiRender()
{
	YT_PROFILE_FUNCTION();
	ImGui::Begin("Setting");
	ImGui::ColorEdit4("Color", glm::value_ptr(m_SquareColor));
	for (auto& res : m_ProfileResults) {
		char lable[50];
		strcpy(lable, "%.3fms  ");
		strcat(lable, res.Name);
		ImGui::Text(lable, res.Time);
	}
	m_ProfileResults.clear();
	ImGui::End();
}

void Sandbox2D::OnEvent(YOTO::Event& e)
{
	YT_PROFILE_FUNCTION();
	m_CameraController.OnEvent(e);
}

cool! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1531982.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux:Prometheus的源码包安装及操作(2)

环境介绍 三台centos 7系统&#xff0c;运行内存都2G 1.prometheus监控服务器&#xff1a;192.168.6.1 主机名&#xff1a;pm 2.grafana展示服务器:192.168.6.2 主机名&#xff1a;gr 3.被监控服务器&#xff1a;192.168.6.3 …

产生三相任意相位差和任意相同占空比的PWM波形

整体思路 将整个PWM周期分为若干个小循环周期。划分的目的就是在任意小循环周期中&#xff0c;任何一相都不会发生0 --> 1 --> 0或1 --> 0 --> 1 电平变化超过两次的情况。 至少需要两个定时器&#xff0c;一个通用/高级定时器具有输出比较功能&#xff0c;另一…

力扣--最小覆盖子串--双端队列+滑动窗口

滑动窗口思路&#xff08;双端队列实现&#xff09;&#xff1a; 可以参考一下&#xff1a;力扣hot8---滑动窗口-CSDN博客以及力扣hot9---滑动窗口-CSDN博客。 使用滑动窗口有以下几个步骤&#xff1a;初始化双端队列&#xff08;将s的前t_len个元素入队&#xff0c;此时检验是…

竞赛 - 基于机器视觉的图像拼接算法

前言 图像拼接在实际的应用场景很广&#xff0c;比如无人机航拍&#xff0c;遥感图像等等&#xff0c;图像拼接是进一步做图像理解基础步骤&#xff0c;拼接效果的好坏直接影响接下来的工作&#xff0c;所以一个好的图像拼接算法非常重要。 再举一个身边的例子吧&#xff0c;…

算法·动态规划Dynamic Programming

很多人听到动态规划或者什么dp数组了&#xff0c;或者是做到一道关于动态规划的题目时&#xff0c;就会有一种他很难且不好解决的恐惧心理&#xff0c;但是如果我们从基础的题目开始深入挖掘动规思想&#xff0c;在后边遇到动态规划的难题时就迎难而解了。  其实不然&#xff…

数据库关系运算理论:关系数据操作与关系完整性概念解析

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

王者荣耀使用的UDP通信,十几年编程没用过的协议

缘起 最近在查阅moba相关的资料时&#xff0c;看到了一篇王者荣耀的研发同学的技术分享&#xff0c;从文章中了解到王者荣耀的通信方式是UDP通信&#xff0c;回想到整个职业生涯&#xff0c;貌似并没有用过&#xff0c;今天特地整理下。 udp技术细节 udp协议 UDP协议叫做用…

PTA——1075 链表元素分类、1105 链表合并、1110 区块反转

1075 链表元素分类 解决代码 #include<bits/stdc.h> using namespace std; struct node{int v;int next; }; map<int,node> s; vector<vector<pair<int,int>>> ans(3); vector<pair<int,int>> w; int main(){int st,n,k;cin>>…

web容器导论

一、基础概念 1.Web容器是什么&#xff1f; 让我们先来简单回顾一下Web技术的发展历史&#xff0c;可以帮助你理解Web容器的由来。 早期的Web应用主要用于浏览新闻等静态页面&#xff0c;HTTP服务器&#xff08;比如Apache、Nginx&#xff09;向浏览器返回静态HTML&#xff…

【A-003】基于SSH的校园报刊亭进销存管理系统(含论文)

【A-003】基于SSH的校园报刊亭进销存管理系统&#xff08;含论文&#xff09; 开发环境&#xff1a; Eclipse/MyEclipse、Tomcat8、Jdk1.8 数据库&#xff1a; MySQL 适用于&#xff1a; 课程设计&#xff0c;毕业设计&#xff0c;学习等等 系统介绍 功能需求 系统架构图…

TCP协议 及 重要机制

目录 1.TCP 协议报文格式 1.1.端口号 1.2 首部长度 和 选项 1.3 保留位 1.4 检验和 1.5 32位序号和确认序号 2. TCP的重要机制 2.1 确认应答 2.2 超时重传 2.3 连接管理 2.3.1 三次握手 2.3.2 四次挥手 2.4 滑动窗口 2.5 流量控制 2.6 拥塞控制 2.7 延时应答 2…

投简历没回复?9位DBA公众号集结,快上车!

&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&#x1f61c;&#x1f61c; 中国DBA联盟(ACD…

蓝桥杯之简单数论冲刺

文章目录 取模快速幂 取模 这道题目有两个注意点&#xff1a; 1.当你的取模之后刚好等于0的话&#xff0c;后面就不用进行后面的计算 2.if sum detail[i] > q: 这个语句的等号也很重要 import os import sys# 请在此输入您的代码a,b,n map(int,input().split())week a*5 …

slab分配器

什么是slab分配器&#xff1f; 用户态程序可以使用malloc及其在C标准库中的相关函数申请内存&#xff1b;内核也需要经常分配内存&#xff0c;但无法使用标准库函数&#xff1b;linux内核中&#xff0c;伙伴分配器是一种页分配器&#xff0c;是以页为单位的&#xff0c;但这个…

全网良心开源知识库:AI学习者的宝藏之地

导语&#xff1a;在这个信息爆炸的时代&#xff0c;想要入门AI&#xff0c;找到最一流的学习资源并非易事。然而&#xff0c;有一个地方&#xff0c;能让你免费学习AI&#xff0c;获取最顶尖的知识&#xff0c;还能加入最优秀的AI学习圈。今天&#xff0c;我要向大家推荐的&…

05.自定义指令,插槽和路由配置

一、学习目标 1.自定义指令 基本语法&#xff08;全局、局部注册&#xff09;指令的值v-loading的指令封装 2.插槽 默认插槽具名插槽作用域插槽 3.综合案例&#xff1a;商品列表 MyTag组件封装MyTable组件封装 4.路由入门 单页应用程序路由VueRouter的基本使用 一、自…

大数据 - Spark系列《十四》- spark集群部署模式

Spark系列文章&#xff1a; 大数据 - Spark系列《一》- 从Hadoop到Spark&#xff1a;大数据计算引擎的演进-CSDN博客 大数据 - Spark系列《二》- 关于Spark在Idea中的一些常用配置-CSDN博客 大数据 - Spark系列《三》- 加载各种数据源创建RDD-CSDN博客 大数据 - Spark系列《…

C语言例3-35:长度运算的例子

长度运算符的表现形式&#xff1a; sizeof(数据类型符&#xff09; 或 sizeof(变量&#xff09; 长度运算符的优先级&#xff1a; 与单目算术运算符、单目逻辑运算符、自增和自减运算符的优先级相同。上述优先级相同的运算符的结合性都是从右至左。 长度运算的例子 代码如…

【漏洞复现】Progress Kemp LoadMaster 命令注入漏洞(CVE-2024-1212)

0x01 产品简介 Progress Kemp LoadMaster是一款高性能的应用交付控制器&#xff0c;具有可扩展性&#xff0c;支持实体硬件和虚拟机的负载均衡。它提供了当今应用服务所需的各种功能&#xff0c;包括深度用户验证、资安防护&#xff08;如WAF/IPS/DDoS防护&#xff09;以及零信…

如何写出干净的 Git Commit

大家好&#xff0c;我是楷鹏。 写一份干净的 Git Commit&#xff0c;不仅赏心悦目&#xff0c;也有诸多好处&#xff0c;比如 为项目或者仓库生成 change log方便在其他一些 Git 工具使用&#xff0c;比如 CI/CD、代码协作和审计平台、发版工具等 这是 AngularJS 仓库的 Git …