抽象:
Shader.h:
#pragma once
#include <string>
namespace YOTO {
class Shader {
public:
virtual~Shader()=default;
virtual void Bind()const=0;
virtual void UnBind()const=0;
static Shader* Create(const std::string& vertexSrc, const std::string& fragmentSrc);
}
;
}
Shader.cpp:
#include "ytpch.h"
#include "Shader.h"
#include"Renderer.h"
#include "Platform/OpenGL/OpenGLShader.h"
namespace YOTO {
Shader* Shader::Create(const std::string& vertexSrc, const std::string& fragmentSrc)
{
switch (Renderer::GetAPI())
{
case RendererAPI::API::None:
YT_CORE_ASSERT(false, "Buffer:API为None不支持");
return nullptr;
case RendererAPI::API::OpenGL:
return new OpenGLShader(vertexSrc, fragmentSrc);
}
YT_CORE_ASSERT(false, "Buffer:未知API");
return nullptr;
}
}
实现:
新建OpenGLShader类:
OpenGLShader.h
#pragma once
#include <string>
#include "YOTO/Renderer/Shader.h"
#include <glm/glm.hpp>
namespace YOTO {
class OpenGLShader:public Shader {
public:
OpenGLShader(const std::string& vertexSrc, const std::string& fragmentSrc);
~OpenGLShader();
void Bind()const override;
void UnBind()const override;
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:
uint32_t m_RendererID;
}
;
}
OpenGLShader.cpp
#include "ytpch.h"
#include "OpenGLShader.h"
#include <glad/glad.h>
#include <YOTO/Log.h>
#include<glm/gtc/type_ptr.hpp>
namespace YOTO {
OpenGLShader::OpenGLShader(const std::string& vertexSrc, const std::string& fragmentSrc)
{
// 1.1.创建顶点着色器对象
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
// Send the vertex shader source code to GL
// Note that std::string's .c_str is NULL character terminated.
// 1.2.附加顶点着色器源码到顶点着色器对象中
const GLchar* source = vertexSrc.c_str();
glShaderSource(vertexShader, 1, &source, 0);
// 1.3.编译顶点着色器对象
glCompileShader(vertexShader);
// 1.4.检查是否编译成功
GLint isCompiled = 0;
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE) {
// 1.4.2编译失败可以打印报错信息
GLint maxLength = 0;
glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength);
// The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetShaderInfoLog(vertexShader, maxLength, &maxLength, &infoLog[0]);
// We don't need the shader anymore.
glDeleteShader(vertexShader);
YT_CORE_ERROR("{0}", infoLog.data());
YT_CORE_ASSERT(false, "Vertex shader compilation failure!");
return;
}
// 片段着色器一样
// 2.1.创建片段着色器对象
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
// Send the fragment shader source code to GL
// Note that std::string's .c_str is NULL character terminated.
// 2.2.附加片段着色器源码到片段着色器对象中
source = fragmentSrc.c_str();
glShaderSource(fragmentShader, 1, &source, 0);
// 2.3.编译片段着色器对象
glCompileShader(fragmentShader);
// 2.4.检查是否编译成功
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &isCompiled);
if (isCompiled == GL_FALSE) {
// 2.4.2编译失败可以打印报错信息
GLint maxLength = 0;
glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &maxLength);
// The maxLength includes the NULL character
std::vector<GLchar> infoLog(maxLength);
glGetShaderInfoLog(fragmentShader, maxLength, &maxLength, &infoLog[0]);
// We don't need the shader anymore.
glDeleteShader(fragmentShader);
// Either of them. Don't leak shaders.
glDeleteShader(vertexShader);
YT_CORE_ERROR("{0}", infoLog.data());
YT_CORE_ASSERT(false, "Fragment shader compilation failure!");
return;
}
// Vertex and fragment shaders are successfully compiled.
// Now time to link them together into a program.
// Get a program object.
// 3.1创建着色器程序对象
m_RendererID = glCreateProgram();
GLuint program = m_RendererID;
// 3.2附加着色器对象给着色器程序对象
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
// 3.3链接着色器程序对象
glLinkProgram(program);
// 3.4可以检查链接是否成功
// 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 character
std::vector<GLchar> infoLog(maxLength);
glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
// We don't need the program anymore.
glDeleteProgram(program);
// Don't leak shaders either.
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
YT_CORE_ERROR("{0}", infoLog.data());
YT_CORE_ASSERT(false, "Shader link failure!");
return;
}
// 4.删除着色器对象
// Always detach shaders after a successful link.
glDetachShader(program, vertexShader);
glDetachShader(program, fragmentShader);
}
OpenGLShader::~OpenGLShader()
{
glDeleteProgram(m_RendererID);
}
void OpenGLShader::Bind() const
{
glUseProgram(m_RendererID);
}
void OpenGLShader::UnBind() const
{
glUseProgram(0);
}
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);
}
}
测试:
#include<YOTO.h>
#include "imgui/imgui.h"
#include<stdio.h>
#include <glm/gtc/matrix_transform.hpp>
#include <Platform/OpenGL/OpenGLShader.h>
#include <glm/gtc/type_ptr.hpp>
class ExampleLayer:public YOTO::Layer
{
public:
ExampleLayer()
:Layer("Example"), m_Camera(-2.0f, 2.0f, -2.0f, 2.0f), m_CameraPosition(0){
uint32_t indices[3] = { 0,1,2 };
float vertices[3 * 7] = {
-0.5f,-0.5f,0.0f, 0.8f,0.2f,0.8f,1.0f,
0.5f,-0.5f,0.0f, 0.2f,0.3f,0.8f,1.0f,
0.0f,0.5f,0.0f, 0.8f,0.8f,0.2f,1.0f,
};
m_VertexArray.reset(YOTO::VertexArray::Create());
std::shared_ptr<YOTO::VertexBuffer> m_VertexBuffer;
m_VertexBuffer.reset(YOTO::VertexBuffer::Create(vertices, sizeof(vertices)));
{
YOTO::BufferLayout setlayout = {
{YOTO::ShaderDataType::Float3,"a_Position"},
{YOTO::ShaderDataType::Float4,"a_Color"}
};
m_VertexBuffer->SetLayout(setlayout);
}
m_VertexArray->AddVertexBuffer(m_VertexBuffer);
std::shared_ptr<YOTO::IndexBuffer>m_IndexBuffer;
m_IndexBuffer.reset(YOTO::IndexBuffer::Create(indices, sizeof(indices) / sizeof(uint32_t)));
m_VertexArray->AddIndexBuffer(m_IndexBuffer);
std::string vertexSource = R"(
#version 330 core
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec4 a_Color;
uniform mat4 u_ViewProjection;
uniform mat4 u_Transform;
out vec3 v_Position;
out vec4 v_Color;
void main(){
v_Position=a_Position;
v_Color=a_Color;
gl_Position =u_ViewProjection *u_Transform* vec4( a_Position,1.0);
}
)";
//绘制颜色
std::string fragmentSource = R"(
#version 330 core
layout(location = 0) out vec4 color;
in vec3 v_Position;
in vec4 v_Color;
void main(){
color=vec4(v_Color);
}
)";
m_Shader.reset(YOTO::Shader::Create(vertexSource, fragmentSource));
///测试/
m_SquareVA.reset(YOTO::VertexArray::Create());
float squareVertices[3 * 4] = {
-0.5f,-0.5f,0.0f,
0.5f,-0.5f,0.0f,
0.5f,0.5f,0.0f,
-0.5f,0.5f,0.0f
};
std::shared_ptr<YOTO::VertexBuffer> squareVB;
squareVB.reset(YOTO::VertexBuffer::Create(squareVertices, sizeof(squareVertices)));
squareVB->SetLayout({
{YOTO::ShaderDataType::Float3,"a_Position"}
});
m_SquareVA->AddVertexBuffer(squareVB);
uint32_t squareIndices[6] = { 0,1,2,2,3,0 };
std::shared_ptr<YOTO::IndexBuffer> squareIB;
squareIB.reset((YOTO::IndexBuffer::Create(squareIndices, sizeof(squareIndices) / sizeof(uint32_t))));
m_SquareVA->AddIndexBuffer(squareIB);
//测试:
std::string BlueShaderVertexSource = R"(
#version 330 core
layout(location = 0) in vec3 a_Position;
uniform mat4 u_ViewProjection;
uniform mat4 u_Transform;
out vec3 v_Position;
void main(){
v_Position=a_Position;
gl_Position =u_ViewProjection*u_Transform*vec4( a_Position,1.0);
}
)";
//绘制颜色
std::string BlueShaderFragmentSource = R"(
#version 330 core
layout(location = 0) out vec4 color;
in vec3 v_Position;
uniform vec3 u_Color;
void main(){
color=vec4(u_Color,1.0);
}
)";
m_BlueShader.reset(YOTO::Shader::Create(BlueShaderVertexSource, BlueShaderFragmentSource));
}
void OnImGuiRender() override {
ImGui::Begin("设置");
ImGui::ColorEdit3("正方形颜色", glm::value_ptr(m_SquareColor));
ImGui::End();
}
void OnUpdate(YOTO::Timestep ts)override {
YT_CLIENT_TRACE("delta time {0}s ({1}ms)", ts.GetSeconds(), ts.GetMilliseconds());
if (YOTO::Input::IsKeyPressed(YT_KEY_LEFT)) {
m_CameraPosition.x -= m_CameraMoveSpeed* ts;
}
else if (YOTO::Input::IsKeyPressed(YT_KEY_RIGHT)) {
m_CameraPosition.x += m_CameraMoveSpeed * ts;
}
if (YOTO::Input::IsKeyPressed(YT_KEY_DOWN)) {
m_CameraPosition.y -= m_CameraMoveSpeed * ts;
}
else if (YOTO::Input::IsKeyPressed(YT_KEY_UP)) {
m_CameraPosition.y += m_CameraMoveSpeed * ts;
}
if (YOTO::Input::IsKeyPressed(YT_KEY_A)) {
m_CameraRotation += m_CameraRotationSpeed * ts;
}else if (YOTO::Input::IsKeyPressed(YT_KEY_D)) {
m_CameraRotation -= m_CameraRotationSpeed * ts;
}
YOTO::RenderCommand::SetClearColor({ 0.2f, 0.2f, 0.2f, 1.0f });
YOTO::RenderCommand::Clear();
m_Camera.SetPosition(m_CameraPosition);
m_Camera.SetRotation(m_CameraRotation);
YOTO::Renderer::BeginScene(m_Camera);
{
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);
/* YOTO::MaterialRef material = new YOTO::MaterialRef(m_FlatColorShader);
YOTO::MaterialInstaceRef mi = new YOTO::MaterialInstaceRef(material);
mi.setValue("u_Color",redColor);
mi.setTexture("u_AlbedoMap", texture);
squreMesh->SetMaterial(mi);*/
std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_BlueShader)->Bind();
std::dynamic_pointer_cast<YOTO::OpenGLShader>(m_BlueShader)->UploadUniformFloat3("u_Color",m_SquareColor);
for (int y = 0; y < 20; y++) {
for (int x = 0; x <20; x++)
{
glm::vec3 pos(x * 0.11f,y* 0.11f, 0.0);
glm::mat4 transform = glm::translate(glm::mat4(1.0f), pos) * scale;
/*if (x % 2 == 0) {
m_BlueShader->UploadUniformFloat4("u_Color", redColor);
}
else {
m_BlueShader->UploadUniformFloat4("u_Color", blueColor);
}*/
YOTO::Renderer::Submit(m_BlueShader, m_SquareVA, transform);
}
}
YOTO::Renderer::Submit(m_Shader, m_VertexArray);
YOTO::Renderer::EndScene();
}
}
void OnEvent(YOTO::Event& event)override {
/*if (event.GetEventType() == YOTO::EventType::KeyPressed) {
YOTO:: KeyPressedEvent& e = (YOTO::KeyPressedEvent&)event;
YT_CLIENT_TRACE("ExampleLayer:{0}",(char)e.GetKeyCode());
if (e.GetKeyCode()==YT_KEY_TAB) {
YT_CLIENT_INFO("ExampleLayerOnEvent:TAB按下了");
}}*/
//YT_CLIENT_TRACE("SandBoxApp:测试event{0}", event);
}
private:
std::shared_ptr<YOTO::Shader> m_Shader;
std::shared_ptr<YOTO::VertexArray> m_VertexArray;
std::shared_ptr<YOTO::Shader> m_BlueShader;
std::shared_ptr<YOTO::VertexArray> m_SquareVA;
YOTO::OrthographicCamera m_Camera;
glm::vec3 m_CameraPosition;
float m_CameraMoveSpeed = 5.0f;
float m_CameraRotation = 0;
float m_CameraRotationSpeed = 180.0f;
glm::vec3 m_SquareColor = { 0.2f,0.3f,0.7f };
};
class Sandbox:public YOTO::Application
{
public:
Sandbox(){
PushLayer(new ExampleLayer());
//PushLayer(new YOTO::ImGuiLayer());
}
~Sandbox() {
}
private:
};
YOTO::Application* YOTO::CreateApplication() {
printf("helloworld");
return new Sandbox();
}
cool!
小修改:
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>;
}
之后把所有share_ptr的地方改成Ref就好了。