跟着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类…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...

如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
【生成模型】视频生成论文调研
工作清单 上游应用方向:控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...