跟着cherno手搓游戏引擎【25】封装2DRenderer,封装shader传参,自定义Texture
封装2DRenderer:
Renderer.h:
#include"ytpch.h"
#include"Renderer.h"
#include <Platform/OpenGL/OpenGLShader.h>
#include"Renderer2D.h"
namespace YOTO {Renderer::SceneData* Renderer::m_SceneData = new Renderer::SceneData;void Renderer::Init(){RenderCommand::Init();Renderer2D::Init();}void Renderer::OnWindowResize(uint32_t width, uint32_t height){RenderCommand::SetViewport(0, 0, width, height);}void Renderer::BeginScene(OrthographicCamera& camera){m_SceneData->ViewProjectionMatrix = camera.GetViewProjectionMatrix();}void Renderer::EndScene(){}void Renderer::Submit(const Ref<Shader>& shader, const Ref<VertexArray>& vertexArray, const glm::mat4& transform){shader->Bind();std::dynamic_pointer_cast<OpenGLShader>(shader)->UploadUniformMat4("u_ViewProjection", m_SceneData->ViewProjectionMatrix);std::dynamic_pointer_cast<OpenGLShader>(shader)->UploadUniformMat4("u_Transform", transform);/* mi.Bind();*/vertexArray->Bind();RenderCommand::DrawIndexed(vertexArray);}
}
Renderer2D.h:专门渲染2D的类,负责“画什么”的问题
#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 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);static void DrawQuad(const glm::vec3& position, const glm::vec2& size, const Ref<Texture2D> texture);private:private:};
}
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 {struct Renderer2DStorage {Ref<VertexArray> QuadVertexArray;//Ref<Shader> FlatColorShader;Ref<Shader> TextureShader;Ref<Texture2D> WhiteTexture;};static Renderer2DStorage* s_Data;void Renderer2D::Init(){s_Data = new Renderer2DStorage();s_Data->QuadVertexArray = VertexArray::Create();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,};Ref<VertexBuffer> squareVB;squareVB.reset(VertexBuffer::Create(squareVertices, sizeof(squareVertices)));squareVB->SetLayout({{ShaderDataType::Float3,"a_Position"},{ShaderDataType::Float2,"a_TexCoord"}});s_Data->QuadVertexArray->AddVertexBuffer(squareVB);uint32_t squareIndices[6] = { 0,1,2,2,3,0 };Ref<IndexBuffer> squareIB;squareIB.reset((IndexBuffer::Create(squareIndices, sizeof(squareIndices) / sizeof(uint32_t))));s_Data->QuadVertexArray->AddIndexBuffer(squareIB);s_Data->WhiteTexture = Texture2D::Create(1, 1);uint32_t whiteTextureData = 0xffffffff;s_Data->WhiteTexture->SetData(&whiteTextureData,sizeof(uint32_t));//s_Data->FlatColorShader =Shader::Create("assets/shaders/FlatColor.glsl");s_Data->TextureShader= Shader::Create("assets/shaders/Texture.glsl");s_Data->TextureShader->Bind();s_Data->TextureShader->SetInt("u_Texture", 0);}void Renderer2D::ShutDown(){delete s_Data;}void Renderer2D::BeginScene(const OrthographicCamera& camera){/*s_Data->FlatColorShader->Bind();s_Data->FlatColorShader->SetMat4("u_ViewProjection",camera.GetViewProjectionMatrix());*/s_Data->TextureShader->Bind();s_Data->TextureShader->SetMat4("u_ViewProjection", camera.GetViewProjectionMatrix());}void Renderer2D::EndScene(){}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){//s_Data->FlatColorShader->Bind();//s_Data->FlatColorShader->SetFloat4("u_Color", color);//s_Data->TextureShader->Bind();s_Data->TextureShader->SetFloat4("u_Color", color);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){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();s_Data->TextureShader->SetFloat4("u_Color", {0.2f,0.3f,0.8f,0.5f});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);}
}
封装Shader传参:
Shader.h:添加SetInt、SetFloat3...等等Set方法
#pragma once
#include <string>
#include<glm/glm.hpp>
namespace YOTO {class Shader {public:virtual~Shader()=default;virtual void Bind()const=0;virtual void UnBind()const=0;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;virtual const std::string& GetName()const = 0;static Ref<Shader> Create(const std::string& filepath);static Ref<Shader> Create(const std::string&name, const std::string& vertexSrc, const std::string& fragmentSrc);};class ShaderLibrary {public:void Add(const Ref<Shader>& shader);void Add(const std::string &name,const Ref<Shader>& shader);Ref<Shader> Load(const std::string filepath);Ref<Shader> Load(const std::string &name,const std::string filepath);Ref<Shader> Get(const std::string& name);bool Exists(const std::string& name);private:std::unordered_map<std::string,Ref<Shader>> m_Shaders;};
}
OpenGLShader.h:同Shader.h
#pragma once
#include <string>
#include "YOTO/Renderer/Shader.h"
#include <glm/glm.hpp>
typedef unsigned int GLenum;
namespace YOTO {class OpenGLShader:public Shader {public:OpenGLShader(const std::string& filepath);OpenGLShader(const std::string &name,const std::string& vertexSrc, const std::string& fragmentSrc);~OpenGLShader();void Bind()const override;void UnBind()const override;virtual void SetInt(const std::string& name, int value) override;virtual void SetFloat3(const std::string& name, const glm::vec3& value) override;virtual void SetFloat4(const std::string& name, const glm::vec4& value)override;virtual void SetMat4(const std::string& name, const glm::mat4& value) override;virtual const std::string& GetName()const override { return m_Name; }void UploadUniformMat4(const std::string& name, const glm::mat4& matrix);void UploadUniformMat3(const std::string& name, const glm::mat3& matrix);void UploadUniformFloat4(const std::string& name, const glm::vec4& values);void UploadUniformFloat3(const std::string& name, const glm::vec3& values);void UploadUniformFloat2(const std::string& name, const glm::vec2& values);void UploadUniformFloat(const std::string& name, float values);void UploadUniformInt(const std::string& name, int values);private:std::string ReadFile(const std::string filepath);std::unordered_map<GLenum,std::string> PreProcess(const std::string& source);void Compile(const std::unordered_map<GLenum, std::string>& shaderSources);private:uint32_t m_RendererID;std::string m_Name;};
}
OpenGLShader.cpp:
#include "ytpch.h"
#include "OpenGLShader.h"#include <glad/glad.h>
#include<glm/gtc/type_ptr.hpp>
namespace YOTO {static GLenum ShaderTypeFromString(const std::string& type) {if (type == "vertex") {return GL_VERTEX_SHADER;}if (type == "fragment" || type == "pixel") {return GL_FRAGMENT_SHADER;}YT_CORE_ASSERT(false, "不知道的shader类型");return 0;}OpenGLShader::OpenGLShader(const std::string& filepath){std::string source = ReadFile(filepath);YT_CORE_ASSERT(source.size(), "GLSL读取的字符串为空");auto shaderSources = PreProcess(source);Compile(shaderSources);auto lastSlash = filepath.find_last_of("/\\");lastSlash = lastSlash == std::string::npos ? 0 : lastSlash + 1;auto lastDot = filepath.rfind('.');auto count = lastDot == std::string::npos ? filepath.size() - lastSlash : lastDot - lastSlash;m_Name=filepath.substr(lastSlash, count);}OpenGLShader::OpenGLShader(const std::string& name, const std::string& vertexSrc, const std::string& fragmentSrc):m_Name(name){std::unordered_map<GLenum, std::string >sources;sources[GL_VERTEX_SHADER] = vertexSrc;sources[GL_FRAGMENT_SHADER] = fragmentSrc;Compile(sources);}OpenGLShader::~OpenGLShader(){glDeleteProgram(m_RendererID);}std::string OpenGLShader::ReadFile(const std::string filepath){std::string result;std::ifstream in(filepath, std::ios::in | std::ios::binary);if (in) {in.seekg(0, std::ios::end); // 将指针放在最后面result.resize(in.tellg()); // 初始化string的大小, in.tellg()返回位置in.seekg(0, std::ios::beg); // in指回头部in.read(&result[0], result.size()); // in读入放在result指向的内存中}else {YT_CORE_ERROR("不能打开文件:{0}", filepath);}return result;}std::unordered_map<GLenum, std::string> OpenGLShader::PreProcess(const std::string& source){std::unordered_map<GLenum, std::string> shaderSources;std::string typeToken = "#type";size_t typeTokenLen = typeToken.size();size_t findCurPos = source.find(typeToken, 0);size_t findNextPos = findCurPos;while (findNextPos != std::string::npos) {size_t curlineEndPos = source.find_first_of("\r\n", findCurPos);///r/n写错为/r/nYT_CORE_ASSERT(curlineEndPos != std::string::npos, "解析shader失败");size_t begin = findCurPos + typeTokenLen + 1;std::string type = source.substr(begin, curlineEndPos - begin);// 获取到是vertex还是fragmentYT_CORE_ASSERT(ShaderTypeFromString(type), "无效的shader的类型 ");size_t nextLinePos = source.find_first_not_of("\r\n", curlineEndPos);findNextPos = source.find(typeToken, nextLinePos);// 获取到具体的shader代码shaderSources[ShaderTypeFromString(type)] = source.substr(nextLinePos, findNextPos - (nextLinePos == std::string::npos ? source.size() - 1 : nextLinePos));findCurPos = findNextPos;}return shaderSources;/*用find,而不是find_firtst_of,因为find返回完全匹配的字符串的的位置;find_first_of返回被查匹配字符串中某个字符的第一次出现位置。std::string::npos是一个非常大的数source.substr(0, source.size() + 10000)截取到从头到末尾,不会报错*/}void OpenGLShader::Compile(const std::unordered_map<GLenum, std::string>& shaderSources){GLuint program = glCreateProgram();YT_CORE_ASSERT(shaderSources.size()<=2,"OpenGLShader:shader只支持两种!")std::array<GLenum,2>glShaderIDs;int glShaderIDIndex=0;for (auto& kv : shaderSources) {GLenum type = kv.first;const std::string& source = kv.second;// Create an empty vertex shader handleGLuint shader = glCreateShader(type);// Send the vertex shader source code to GL// Note that std::string's .c_str is NULL character terminated.const GLchar* sourceCStr = source.c_str();glShaderSource(shader, 1, &sourceCStr, 0);// Compile the vertex shaderglCompileShader(shader);GLint isCompiled = 0;glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);if (isCompiled == GL_FALSE){GLint maxLength = 0;glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);// The maxLength includes the NULL characterstd::vector<GLchar> infoLog(maxLength);glGetShaderInfoLog(shader, maxLength, &maxLength, &infoLog[0]);// We don't need the shader anymore.glDeleteShader(shader);// Use the infoLog as you see fit.// In this simple program, we'll just leaveYT_CORE_ERROR("{0} ", infoLog.data());YT_CORE_ASSERT(false, "shader 编译失败!");break;}// Attach our shaders to our programglAttachShader(program, shader);glShaderIDs[glShaderIDIndex++]=shader;}// Link our programglLinkProgram(program);// Note the different functions here: glGetProgram* instead of glGetShader*.GLint isLinked = 0;glGetProgramiv(program, GL_LINK_STATUS, (int*)&isLinked);if (isLinked == GL_FALSE){GLint maxLength = 0;glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);// The maxLength includes the NULL characterstd::vector<GLchar> infoLog(maxLength);glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);// We don't need the program anymore.glDeleteProgram(program);// Don't leak shaders either.for (auto id : glShaderIDs) {glDeleteShader(id);}// Use the infoLog as you see fit.// In this simple program, we'll just leaveYT_CORE_ERROR("{0} ", infoLog.data());YT_CORE_ASSERT(false, "shader link failure!");return;}// Always detach shaders after a successful link.for (auto id : glShaderIDs) {glDetachShader(program, id);}m_RendererID = program;}void OpenGLShader::Bind() const{glUseProgram(m_RendererID);}void OpenGLShader::UnBind() const{glUseProgram(0);}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);}void OpenGLShader::UploadUniformMat4(const std::string& name, const glm::mat4& matrix){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniformMatrix4fv(loacation, 1, GL_FALSE, glm::value_ptr(matrix));}void OpenGLShader::UploadUniformMat3(const std::string& name, const glm::mat3& matrix){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniformMatrix3fv(loacation, 1, GL_FALSE, glm::value_ptr(matrix)); }void OpenGLShader::UploadUniformFloat4(const std::string& name, const glm::vec4& values){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniform4f(loacation, values.x, values.y, values.z, values.w);}void OpenGLShader::UploadUniformFloat3(const std::string& name, const glm::vec3& values){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniform3f(loacation, values.x, values.y, values.z);}void OpenGLShader::UploadUniformFloat2(const std::string& name, const glm::vec2& values){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniform2f(loacation, values.x, values.y);}void OpenGLShader::UploadUniformFloat(const std::string& name, float values){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniform1f(loacation, values);}void OpenGLShader::UploadUniformInt(const std::string& name, int values){GLint loacation = glGetUniformLocation(m_RendererID, name.c_str());glUniform1i(loacation, values);}}
添加自定义Texture方法:
Texture.h:添加新的Create方法:根据宽高添加
#pragma once
namespace YOTO {class Texture{public:virtual ~Texture() = default;virtual uint32_t GetWidth()const = 0;virtual uint32_t GetHeight()const = 0;virtual void SetData(void* data, uint32_t size) = 0;virtual void Bind(uint32_t slot=0)const = 0;};class Texture2D :public Texture {public:static Ref<Texture2D>Create(uint32_t width,uint32_t height);static Ref<Texture2D>Create(const std::string& path);};
}
Texture.cpp:
#include "ytpch.h"
#include "Texture.h"
#include"Renderer.h"
#include "Platform/OpenGL/OpenGLTexture.h"
namespace YOTO {Ref<Texture2D> Texture2D::Create(uint32_t width, uint32_t height){switch (Renderer::GetAPI()){case RendererAPI::API::None:YT_CORE_ASSERT(false, "Texture2D:API为None不支持");return nullptr;case RendererAPI::API::OpenGL:return CreateRef<OpenGLTexture2D>(width,height);}YT_CORE_ASSERT(false, "Buffer:未知API");return nullptr;}Ref<Texture2D> Texture2D::Create(const std::string& path){switch (Renderer::GetAPI()){case RendererAPI::API::None:YT_CORE_ASSERT(false, "Texture2D:API为None不支持");return nullptr;case RendererAPI::API::OpenGL:return CreateRef<OpenGLTexture2D>(path);}YT_CORE_ASSERT(false, "Buffer:未知API");return nullptr;}
}
OpenGLTexture.h:同Texture.h相同,且添加设置texture数据的方法SetData:
#pragma once
#include"YOTO/Renderer/Texture.h"
#include<glad/glad.h>
namespace YOTO {class OpenGLTexture2D:public Texture2D{public:OpenGLTexture2D(uint32_t width,uint32_t height);OpenGLTexture2D(const std::string path);virtual~OpenGLTexture2D();virtual uint32_t GetWidth()const override { return m_Width; }virtual uint32_t GetHeight()const override { return m_Height; }virtual void SetData(void* data, uint32_t size)override;virtual void Bind(uint32_t slot=0)const override;private:std::string m_Path;uint32_t m_Width, m_Height;uint32_t m_RendererID;GLenum m_InternalFormat, m_DataFormat;};
}
OpenGLTexture.cpp:
#include "ytpch.h"
#include "OpenGLTexture.h"
#include<glad/glad.h>
#include"stb_image.h"
namespace YOTO {OpenGLTexture2D::OpenGLTexture2D(uint32_t width, uint32_t height):m_Width(width),m_Height(height){m_InternalFormat = GL_RGBA8;m_DataFormat = GL_RGBA;glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererID);///告诉OpenGLm_RendererID的纹理存储的是rbg8位,宽高的缓冲区glTextureStorage2D(m_RendererID, 1, m_InternalFormat, m_Width, m_Height);//配置参数:纹理放大时用周围颜色的平均值过滤glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST);glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_S, GL_REPEAT);glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);}OpenGLTexture2D::OpenGLTexture2D(const std::string path):m_Path(path){int width, height, channels;stbi_set_flip_vertically_on_load(1);//翻转stbi_uc*data=stbi_load(path.c_str(),&width,&height,&channels,0);YT_CORE_ASSERT(data, "图片加载错误");m_Width = width;m_Height = height;GLenum internalFormat = 0,dataFormat=0;if (channels == 4) {internalFormat = GL_RGBA8;dataFormat = GL_RGBA;}else if (channels==3) {internalFormat = GL_RGB8;dataFormat = GL_RGB;}m_InternalFormat = internalFormat;m_DataFormat = dataFormat;YT_CORE_ASSERT(internalFormat& dataFormat,"OpenGLTexture2D:不支持的颜色格式")//创建纹理glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererID);///告诉OpenGLm_RendererID的纹理存储的是rbg8位,宽高的缓冲区glTextureStorage2D(m_RendererID, 1, internalFormat,m_Width,m_Height);//配置参数:纹理放大时用周围颜色的平均值过滤glTextureParameteri(m_RendererID,GL_TEXTURE_MIN_FILTER,GL_LINEAR);glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST);glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_S, GL_REPEAT);glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height, dataFormat,GL_UNSIGNED_BYTE,data);stbi_image_free(data);}OpenGLTexture2D::~OpenGLTexture2D(){glDeleteTextures(1,&m_RendererID);}void OpenGLTexture2D::SetData(void* data, uint32_t size){uint32_t bpc = m_DataFormat == GL_RGBA ? 4 : 3;YT_CORE_ASSERT(size == m_Width * m_Height * bpc,"OpenGLTexture2D:数据必须是完整的!");glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height,m_DataFormat, GL_UNSIGNED_BYTE,data);}void OpenGLTexture2D::Bind(uint32_t slot) const{glBindTextureUnit(slot, m_RendererID);}
}
Sandbox2D.h:添加m_CheckerboardTexture
#pragma once
#include "YOTO.h"
class Sandbox2D :public YOTO::Layer
{public:Sandbox2D();virtual ~Sandbox2D() = default;virtual void OnAttach()override;virtual void OnDetach()override;void OnUpdate(YOTO::Timestep ts)override;virtual void OnImGuiRender() override;void OnEvent(YOTO::Event& e)override;
private:YOTO::OrthographicCameraController m_CameraController;YOTO::Ref<YOTO::Shader> m_FlatColorShader;YOTO::Ref<YOTO::VertexArray> m_SquareVA;YOTO::Ref<YOTO::Texture2D>m_CheckerboardTexture;glm::vec4 m_SquareColor = { 0.2f,0.3f,0.7f,1.0f };
};
化简Sandbox2D:
Sandbox2D.cpp:把传shader参数的代码注释掉 ,统一使用DrawQuad封装;负责“怎么画”的问题:
#include "Sandbox2D.h"
#include <imgui/imgui.h>
#include <glm/gtc/matrix_transform.hpp>
//#include <Platform/OpenGL/OpenGLShader.h>
#include <glm/gtc/type_ptr.hpp>
Sandbox2D::Sandbox2D()
:Layer("Sandbox2D"), m_CameraController(1280.0f / 720.0f, true)
{
}
void Sandbox2D::OnAttach()
{m_CheckerboardTexture = YOTO::Texture2D::Create("assets/textures/Checkerboard.png");}
void Sandbox2D::OnDetach()
{
}void Sandbox2D::OnUpdate(YOTO::Timestep ts)
{ //updatem_CameraController.OnUpdate(ts);//RenderYOTO::RenderCommand::SetClearColor({ 0.2f, 0.2f, 0.2f, 1.0f });YOTO::RenderCommand::Clear();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::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);YOTO::Renderer2D::EndScene();}
}
void Sandbox2D::OnImGuiRender()
{ImGui::Begin("设置");ImGui::ColorEdit4("正方形颜色", glm::value_ptr(m_SquareColor));ImGui::End();
}void Sandbox2D::OnEvent(YOTO::Event& e)
{m_CameraController.OnEvent(e);
}
小修改:
OpenGLRendererAPI.cpp:DrawIndexed中添加解绑Texture:
#include "ytpch.h"
#include "OpenGLRendererAPI.h"
#include <glad/glad.h>
namespace YOTO {void OpenGLRendererAPI::Init(){//启用混合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){glDrawElements(GL_TRIANGLES, vertexArray->GetIndexBuffer()->GetCount(), GL_UNSIGNED_INT, nullptr);glBindTexture(GL_TEXTURE_2D, 0);}
}
flatColor.glsl:
#type vertex#version 330 corelayout(location = 0) in vec3 a_Position;uniform mat4 u_ViewProjection;uniform mat4 u_Transform;void main(){gl_Position =u_ViewProjection*u_Transform*vec4( a_Position,1.0);}#type fragment#version 330 corelayout(location = 0) out vec4 color;uniform vec4 u_Color ;void main(){color =u_Color; }
Texture.glsl:
#type vertex#version 330 corelayout(location = 0) in vec3 a_Position;layout(location = 1) in vec2 a_TexCoord;uniform mat4 u_ViewProjection;uniform mat4 u_Transform;out vec2 v_TexCoord;out vec3 v_Position;void main(){v_TexCoord=a_TexCoord;v_Position=a_Position;gl_Position =u_ViewProjection*u_Transform*vec4( a_Position,1.0);}#type fragment#version 330 corelayout(location = 0) out vec4 color;in vec3 v_Position;in vec2 v_TexCoord;uniform vec4 u_Color ;uniform sampler2D u_Texture ;void main(){color = texture(u_Texture, v_TexCoord*10.0f)*u_Color; }
YOTO.h:添加:
#include"YOTO/Renderer/Renderer2D.h"
Core.h:
#pragma once
#include<memory>
//用于dll的宏
#ifdef YT_PLATFORM_WINDOWS
#if YT_DYNAMIC_LINK#ifdef YT_BUILD_DLL#define YOTO_API __declspec(dllexport) #else#define YOTO_API __declspec(dllimport) #endif // DEBUG
#else#define YOTO_API
#endif
#else
#error YOTO_ONLY_SUPPORT_WINDOWS
#endif // YOTO_PLATFORM_WINDOWS#ifdef YT_DEBUG
#define YT_ENABLE_ASSERTS
#endif#ifdef YT_ENABLE_ASSERTS
#define YT_CLIENT_ASSERT(x,...) {if(!(x)){YT_CLIENT_ERROR("断言错误:{0}",__VA_ARGS__);__debugbreak();}}
#define YT_CORE_ASSERT(x,...) {if(!(x)){YT_CORE_ERROR("断言错误:{0}",__VA_ARGS__);__debugbreak();}}
#else
#define YT_CLIENT_ASSERT(x,...)
#define YT_CORE_ASSERT(x,...)#endif // YT_ENABLE_ASSERTS#define BIT(x)(1<<x)
//绑定事件定义
#define YT_BIND_EVENT_FN(fn) std::bind(&fn, this, std::placeholders::_1)namespace YOTO {template<typename T>using Scope = std::unique_ptr<T>;template<typename T>using Ref = std::shared_ptr<T>;template<typename T,typename ...Args>constexpr Scope<T> CreateScope(Args&&...args) {return std::make_shared<T>(std::forward<Args>(args)...);}template<typename T, typename ...Args>constexpr Ref<T> CreateRef(Args&&...args) {return std::make_shared<T>(std::forward<Args>(args)...);}}
测试:

cool!
相关文章:
跟着cherno手搓游戏引擎【25】封装2DRenderer,封装shader传参,自定义Texture
封装2DRenderer: Renderer.h: #include"ytpch.h" #include"Renderer.h" #include <Platform/OpenGL/OpenGLShader.h> #include"Renderer2D.h" namespace YOTO {Renderer::SceneData* Renderer::m_SceneData new Renderer::S…...
多个值时 if [ -z 报错 binary operator expected
if [ ! -z "\$client_pid" ]; then 报错: line 23: [: 662: binary operator expected 改成 if [[ ! -z "\$client_pid" ]]; then 即可。 unix - binary operator expected error when checking if a file with full pathname exists - Stack Overflo…...
如何使用ChatGPT创建一份优质简历
目录 第一步:明确目标和重点 第二步:与ChatGPT建立对话 第三步:整理生成的内容 第四步:注重行文风格 第五步:强调成就和量化结果 第六步:个性化和定制 第七步:反复修改和完善 总结 在现…...
k8s(6)
目录 一.kubectl 命令行管理K8S 陈述式资源管理方式(可理解成使用一条kubectl命令及其参数选项来实现资源对象的管理操作) service的4的基本类型: service的端口 应用发布策略: 声明式资源管理方式(可理解成使用…...
自动驾驶框架:自动驾驶汽车定位-感知-规划-决策-控制概述,按照我的架构图理解:决策决定的是速度,规划决定的是路径(架构理解推荐)
1.按照我的架构图理解:决策决定的是速度,规划决定的是路径 参考链接:【自动驾驶】运动规划丨速度规划丨自动驾驶速度规划及状态协调方法 2.下面是参考别人的理解: 自动驾驶汽车定位-感知-规划-决策-控制概述 规划-决策-控制知…...
Gemma
Gemma 1.使用2.RAG3.LoRA3.1LoRA分类任务3.2LoRA中文建模任务 1.使用 首先是去HF下载模型,但一直下载不了,所以去了HF镜像网站,下载gemma需要HF的Token,按照步骤就可以下载。代码主要是Kaggle论坛里面的分享内容。 huggingface-…...
淘宝关键词搜索API、搜索商品接口、商品价格监控
淘宝搜索引擎的工作原理: 淘宝搜索引擎的工作原理是基于搜索引擎的核心技术——爬虫和索引,通过对海量数据的抓取、分析和存储,提供给用户最准确的搜索结果。 具体来说,淘宝搜索引擎的工作流程如下: 企业级api数据…...
vue实现水印功能
目录 一、应用场景 二、实现原理 三、详细开发 1.水印的实现方式 2.防止用户通过控制台修改样式去除水印效果(可跳过,有弊端) 3.水印的使用 (1)单页面/全局使用 (2)全局使用个别页面去掉…...
记录一下我的Ruby On Rails的systemd服务脚本
自己也是一个 ROR 框架的学习者,同时也是 Ruby 的新手。对于如何让 ROR 应用随系统自动启动并不是很了解。在尝试了各种方法之后,我最终找到了一条可行的途径。虽然不确定是否完全正确,但服务已经成功启动了。因此,我决定在这里保…...
【计算机网络】传输层——TCP和UDP详解
文章目录 一. TCP和UDP简介二. UDP 协议详解1. UDP报文格式2. UDP的使用场景 三. TCP 协议详解1. TCP报文格式2. TCP协议的重要机制确认应答(保证可靠传输的最核心机制)超时重传连接管理(三次握手、四次挥手)!…...
stm32和嵌入式linux可以同步学习吗?
在开始前我有一些资料,是我根据网友给的问题精心整理了一份「stm3的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!如果需要使用STM32,建…...
maven--->maven中的<properties>属性有什么作用?
🙌🙌🙌🙌🙌🙌 在Maven中,元素用于定义项目中可重用的属性值。这些属性值可以在项目的POM文件中被引用,以便在整个项目中统一管理和使用。通过使用元素,可以避免在POM文件…...
android 网络请求总结
1 先看下基础部分: android okhttp网络访问是基于 tcp/ip 的 最上层是应用层的封装,有http,https(加密),ftp 下面是socket套接字的封装,就是将ip和端口的封装 在下面就是tcp/udp 在下面 ip协议…...
用 Python 自动化处理无聊的事情
“编程最棒的部分就是看到机器做一些有用的事情而获得的胜利。用 Python 将无聊的事情自动化将所有编程视为这些小小的胜利;它让无聊变得有趣。” Hilary Mason,数据科学家兼 Fast Forward Labs 创始人 “我很享受打破东西然后把它们重新组合起来的乐趣…...
稀疏计算、彩票假说、MoE、SparseGPT
稀疏计算可能是未来10年内最有潜力的深度学习方向之一,稀疏计算模拟了对人脑的观察,人脑在处理信息的时候只有少数神经元在活动,多数神经元是不工作的。而稀疏计算的基本思想是:在计算过程中,将一些不重要的参数设置为…...
Git Windows安装教程
Git简介 Git是目前世界上最先进的分布式版本控制系统。它的工作原理 / 流程如下: [ Workspace:工作区 Index / Stage:暂存区 Repository:仓库区(或本地仓库) Remote:远程仓库 ] Git的下载 去 Git 官网下载对应系统的软件了,下…...
iOS高级理论:Runtime应用
一、遍历类的属性,快速归档 在 iOS 中,可以使用 Runtime 遍历类的属性来实现快速的归档(Archiving)操作。归档是将对象转换为数据流以便存储或传输的过程。下面是一个简单的示例,展示如何使用 Runtime 遍历类的属性进…...
php判断和过滤get或者post的html标签,防止跨站点脚本(XSS),链接注入,框架注入等攻击
大部分网站都包含搜索功能,根据用户搜索的词去执行服务端的业务逻辑。如果一些黑客在搜索参数包含链接(a)、嵌入其他网页(iframe)、前端代码(script)等html字符,再加上服务端php不加…...
PySide6实现课堂点名程序
目录 一:实现思路 二:实现代码 三:完整代码和界面 一:实现思路 为了创建一点名程序,并编写一个基本的 GUI 应用程序。新建一个窗口,展在窗口界面添加开始和停止按钮的QPushButton,和展示正在显示的人名QLabel,点击开始时随机显示人名列表中的一个名字并且展示在QLab…...
瑞_Redis_Redis命令
文章目录 1 Redis命令Redis数据结构Redis 的 key 的层级结构1.0 Redis通用命令1.0.1 KEYS1.0.2 DEL1.0.3 EXISTS1.0.4 EXPIRE1.0.5 TTL 1.1 String类型1.1.0 String类型的常见命令1.1.1 SET 和 GET1.1.2 MSET 和 MGET1.1.3 INCR和INCRBY和DECY1.1.4 SETNX1.1.5 SETEX 1.2 Hash类…...
Cursor怎么用?2026零基础入门教程|5步学会AI编程IDE核心功能
摘要 本文解决软件开发者和 AI 应用开发者在 Windows 环境下安装和使用 AI 编程 IDE 的问题,适合想把 Cursor 用到真实开发流程中的读者。读完可以完成 Cursor 安装、模型配置、项目接入和一次真实代码生成验证。 一. 开篇引入 Cursor 是一类典型的 AI 编程 IDE&a…...
告别MATLAB环境:保姆级教程教你用App Designer打包独立EXE(含Runtime配置避坑)
MATLAB App Designer应用打包实战:从开发到分发的全流程指南 在工程计算和科研领域,MATLAB一直是不可或缺的工具。随着App Designer的推出,开发交互式GUI应用变得前所未有的简单。但当你完成了一个优秀的应用后,如何让没有MATLAB环…...
抖音视频批量下载终极指南:三步搞定免费无水印下载
抖音视频批量下载终极指南:三步搞定免费无水印下载 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support.…...
2026最权威的五大AI学术方案推荐榜单
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 根据维普系统针对生成式AI文本的识别特点,要降低文章的AI率,得从语言…...
react-native-shared-element 性能优化技巧:避免闪烁和提升动画流畅度
react-native-shared-element 性能优化技巧:避免闪烁和提升动画流畅度 【免费下载链接】react-native-shared-element Native shared element transition "primitives" for react-native 💫 项目地址: https://gitcode.com/gh_mirrors/re/re…...
题解:AcWing 1192 奖金
本文分享的必刷题目是从蓝桥云课、洛谷、AcWing等知名刷题平台精心挑选而来,并结合各平台提供的算法标签和难度等级进行了系统分类。题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。 欢迎大家订阅我的专栏:算法…...
CogVideoX-2b实战:手把手教你用文字生成高质量短视频,效果惊艳
CogVideoX-2b实战:手把手教你用文字生成高质量短视频,效果惊艳 1. 开启你的AI导演之旅 想象一下,你只需要输入一段文字描述,就能让AI自动生成一段高质量的视频。这不是科幻电影里的场景,而是CogVideoX-2b带给我们的现…...
三步彻底解决惠普OMEN游戏本性能限制:OmenSuperHub终极方案实践指南
三步彻底解决惠普OMEN游戏本性能限制:OmenSuperHub终极方案实践指南 【免费下载链接】OmenSuperHub 使用 WMI BIOS控制性能和风扇速度,自动解除DB功耗限制。 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub 对于追求极致性能的惠普OM…...
Mac与Windows局域网通信障碍?飞秋Mac版让你无缝连接同事电脑
Mac与Windows局域网通信障碍?飞秋Mac版让你无缝连接同事电脑 【免费下载链接】feiq 基于qt实现的mac版飞秋,遵循飞秋协议(飞鸽扩展协议),支持多项飞秋特有功能 项目地址: https://gitcode.com/gh_mirrors/fe/feiq 还在为Mac电脑无法与…...
保姆级教程:用Python脚本自动转换JD9365A初始化代码为RK3568设备树格式
Python自动化实战:JD9365A初始化代码转RK3568设备树全解析 当面对嵌入式Linux驱动开发时,最令人头疼的莫过于那些冗长而重复的寄存器配置工作。以JD9365A这款MIPI屏幕驱动芯片为例,其初始化代码往往包含上百条寄存器操作命令,手动…...
