跟着cherno手搓游戏引擎【18】抽象Shader、项目小修改

抽象:

Shader.h:

#pragma once
#include 

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类:

跟着cherno手搓游戏引擎【18】抽象Shader、项目小修改_第1张图片

OpenGLShader.h

#pragma once
#include 
#include "YOTO/Renderer/Shader.h"
#include 
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 
#include 
#include
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 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 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 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
#include "imgui/imgui.h"
#include
#include 
#include 
#include 
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 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_ptrm_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 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 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(m_BlueShader)->Bind();
			std::dynamic_pointer_cast(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 m_Shader;
	std::shared_ptr m_VertexArray;


	std::shared_ptr m_BlueShader;
	std::shared_ptr 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();
}

跟着cherno手搓游戏引擎【18】抽象Shader、项目小修改_第2张图片

 cool!

小修改:

Core.h:

#pragma once
#include
//用于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<
	using  Scope = std::unique_ptr;
	template
	using  Ref = std::shared_ptr;
}

之后把所有share_ptr的地方改成Ref就好了。

你可能感兴趣的:(游戏引擎)