相机封装:
OrthographicCamera.h:
cpp
#pragma once
#include <glm/glm.hpp>
namespace YOTO {
class OrthographicCamera
{
public:
OrthographicCamera(float left,float right , float bottom,float top);
const glm::vec3& GetPosition()const { return m_Position; }
void SetPosition(const glm::vec3& position) {
m_Position = position;
RecalculateViewMatrix();
}
float GetRotation()const { return m_Rotation; }
void SetRotation(float rotation) {
m_Rotation = rotation;
RecalculateViewMatrix();
}
const glm::mat4& GetProjectionMatrix()const { return m_ProjectionMatrix; }
const glm::mat4& GetViewMatrix()const { return m_ViewMatrix; }
const glm::mat4& GetViewProjectionMatrix()const { return m_ViewProjectionMatrix; }
private:
void RecalculateViewMatrix();
private:
glm::mat4 m_ProjectionMatrix;
glm::mat4 m_ViewMatrix;
glm::mat4 m_ViewProjectionMatrix;
glm::vec3 m_Position = { 0.0f ,0.0f ,0.0f };
float m_Rotation = 0.0f;
};
}
OrthographicCamera.cpp:
cpp
#include "ytpch.h"
#include "OrthographicCamera.h"
#include <glm/gtc/matrix_transform.hpp>
namespace YOTO {
OrthographicCamera::OrthographicCamera(float left, float right, float bottom, float top)
:m_ProjectionMatrix(glm::ortho(left,right,bottom,top)),m_ViewMatrix(1.0f)
{
m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
}
void OrthographicCamera::RecalculateViewMatrix()
{
glm::mat4 transform = glm::translate(glm::mat4(1.0f), m_Position)*
glm::rotate(glm::mat4(1.0f),glm::radians(m_Rotation),glm::vec3(0,0,1));
m_ViewMatrix = glm::inverse(transform);
m_ViewProjectionMatrix = m_ProjectionMatrix * m_ViewMatrix;
}
}
Uniform的封装:
Shader.h:
cpp
#pragma once
#include <string>
#include <glm/glm.hpp>
namespace YOTO {
class Shader {
public:
Shader(const std::string& vertexSrc, const std::string& fragmentSrc);
~Shader();
void Bind()const;
void UnBind()const;
void UploadUniformMat4(const std::string&name, const glm::mat4 & matrix);
private:
uint32_t m_RendererID;
}
;
}
Shader.cpp:
cpp
#include"ytpch.h"
#include "Shader.h"
#include <glad/glad.h>
#include <YOTO/Log.h>
#include<glm/gtc/type_ptr.hpp>
namespace YOTO {
Shader::Shader(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);
}
Shader::~Shader()
{
glDeleteProgram(m_RendererID);
}
void Shader::Bind() const
{
glUseProgram(m_RendererID);
}
void Shader::UnBind() const
{
glUseProgram(0);
}
void Shader::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));
}
}
进一步封装ShaderUniform:
Renderer.h:
cpp
#pragma once
#include"RenderCommand.h"
#include "OrthographicCamera.h"
#include"Shader.h"
namespace YOTO {
class Renderer {
public:
static void BeginScene(OrthographicCamera &camera);
static void EndScene();
static void Submit(const std::shared_ptr<Shader>& shader, const std::shared_ptr<VertexArray>& vertexArray);
inline static RendererAPI::API GetAPI() {
return RendererAPI::GetAPI();
}
private:
struct SceneData {
glm::mat4 ViewProjectionMatrix;
};
static SceneData* m_SceneData;
};
}
Renderer.cpp:
cpp
#include"ytpch.h"
#include"Renderer.h"
namespace YOTO {
Renderer::SceneData* Renderer::m_SceneData = new Renderer::SceneData;
void Renderer::BeginScene(OrthographicCamera& camera)
{
m_SceneData->ViewProjectionMatrix = camera.GetViewProjectionMatrix();
}
void Renderer::EndScene()
{
}
void Renderer::Submit( const std::shared_ptr<Shader>& shader,const std::shared_ptr<VertexArray>& vertexArray)
{
shader->Bind();
shader->UploadUniformMat4("u_ViewProjection", m_SceneData->ViewProjectionMatrix);
vertexArray->Bind();
RenderCommand::DrawIndexed(vertexArray);
}
}
调用:
Application.h:
cpp
#pragma once
#include"Core.h"
#include"Event/Event.h"
#include"Event/ApplicationEvent.h"
#include "YOTO/Window.h"
#include"YOTO/LayerStack.h"
#include"YOTO/ImGui/ImGuiLayer.h"
#include <YOTO/Renderer/Shader.h>
#include <YOTO/Renderer/Buffer.h>
#include <YOTO/Renderer/VertexArray.h>
#include "YOTO/Renderer/OrthographicCamera.h"
namespace YOTO {
class YOTO_API Application
{
public:
Application();
virtual ~Application();
void Run();
void OnEvent(Event &e);
void PushLayer(Layer* layer);
void PushOverlay(Layer* layer);
inline static Application& Get() {return * s_Instance;}
inline Window& GetWindow() { return *m_Window; }
private:
bool OnWindowClosed(WindowCloseEvent& e);
std::unique_ptr<Window> m_Window;
ImGuiLayer * m_ImGuiLayer;
bool m_Running = true;
LayerStack m_LayerStack;
//unsigned int m_VertexArray;
std::shared_ptr<Shader> m_Shader;
std::shared_ptr<VertexArray> m_VertexArray;
std::shared_ptr<Shader> m_BlueShader;
std::shared_ptr<VertexArray> m_SquareVA;
OrthographicCamera m_Camera;
private:
static Application* s_Instance;
};
//在客户端定义
Application* CreateApplication();
}
Application.cpp:
cpp
#include"ytpch.h"
#include "Application.h"
#include"Log.h"
#include "YOTO/Renderer/Renderer.h"
#include"Input.h"
namespace YOTO {
#define BIND_EVENT_FN(x) std::bind(&x, this, std::placeholders::_1)
Application* Application::s_Instance = nullptr;
Application::Application()
:m_Camera(-2.0f,2.0f,-2.0f,2.0f)
{
YT_CORE_ASSERT(!s_Instance, "Application需要为空!")
s_Instance = this;
//智能指针
m_Window = std::unique_ptr<Window>(Window::Creat());
//设置回调函数
m_Window->SetEventCallback(BIND_EVENT_FN(Application::OnEvent));
//new一个Layer,放在最后层进行渲染
m_ImGuiLayer = new ImGuiLayer();
PushOverlay(m_ImGuiLayer);
//unsigned int id;
//glGenBuffers(1, &id);
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(VertexArray::Create());
std::shared_ptr<VertexBuffer> m_VertexBuffer;
m_VertexBuffer.reset(VertexBuffer::Create(vertices, sizeof(vertices)));
{
BufferLayout setlayout = {
{ShaderDataType::Float3,"a_Position"},
{ShaderDataType::Float4,"a_Color"}
};
m_VertexBuffer->SetLayout(setlayout);
}
m_VertexArray->AddVertexBuffer(m_VertexBuffer);
std::shared_ptr<IndexBuffer>m_IndexBuffer;
m_IndexBuffer.reset(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;
out vec3 v_Position;
out vec4 v_Color;
void main(){
v_Position=a_Position;
v_Color=a_Color;
gl_Position =u_ViewProjection*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(new Shader(vertexSource, fragmentSource));
///测试/
m_SquareVA.reset(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<VertexBuffer> squareVB;
squareVB.reset(VertexBuffer::Create(squareVertices, sizeof(squareVertices)));
squareVB->SetLayout({
{ShaderDataType::Float3,"a_Position"}
});
m_SquareVA->AddVertexBuffer(squareVB);
uint32_t squareIndices[6] = { 0,1,2,2,3,0 };
std::shared_ptr<IndexBuffer> squareIB;
squareIB.reset((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;
out vec3 v_Position;
void main(){
v_Position=a_Position;
gl_Position =u_ViewProjection*vec4( a_Position,1.0);
}
)";
//绘制颜色
std::string BlueShaderFragmentSource = R"(
#version 330 core
layout(location = 0) out vec4 color;
in vec3 v_Position;
void main(){
color=vec4(0.2,0.3,0.8,1.0);
}
)";
m_BlueShader.reset(new Shader(BlueShaderVertexSource, BlueShaderFragmentSource));
}
Application::~Application() {
}
/// <summary>
/// 所有的Window事件都会在这触发,作为参数e
/// </summary>
/// <param name="e"></param>
void Application::OnEvent(Event& e) {
//根据事件类型绑定对应事件
EventDispatcher dispatcher(e);
dispatcher.Dispatch<WindowCloseEvent>(BIND_EVENT_FN(Application::OnWindowClosed));
//输出事件信息
YT_CORE_INFO("Application:{0}",e);
for (auto it = m_LayerStack.end(); it != m_LayerStack.begin();) {
(*--it)->OnEvent(e);
if (e.m_Handled)
break;
}
}
bool Application::OnWindowClosed(WindowCloseEvent& e) {
m_Running = false;
return true;
}
void Application::Run() {
WindowResizeEvent e(1280, 720);
if (e.IsInCategory(EventCategoryApplication)) {
YT_CORE_TRACE(e);
}
if (e.IsInCategory(EventCategoryInput)) {
YT_CORE_ERROR(e);
}
while (m_Running)
{
RenderCommand::SetClearColor({0.2f, 0.2f, 0.2f, 1.0f});
RenderCommand::Clear();
m_Camera.SetPosition({0.5f,0.5f, 0.0f });
m_Camera.SetRotation(45);
Renderer::BeginScene(m_Camera);
{
/* m_BlueShader->Bind();
m_BlueShader->UploadUniformMat4("u_ViewProjection",m_Camera.GetViewProjectionMatrix());*/
Renderer::Submit(m_BlueShader,m_SquareVA);
/* m_Shader->Bind();
m_Shader->UploadUniformMat4("u_ViewProjection", m_Camera.GetViewProjectionMatrix());*/
Renderer::Submit(m_Shader,m_VertexArray);
Renderer::EndScene();
}
for (Layer* layer : m_LayerStack) {
layer->OnUpdate();
}
//将ImGui的刷新放到APP中,与Update分开
m_ImGuiLayer->Begin();
for (Layer* layer : m_LayerStack) {
layer->OnImGuiRender();
}
m_ImGuiLayer->End();
m_Window->OnUpdate();
}
}
void Application::PushLayer(Layer* layer) {
m_LayerStack.PushLayer(layer);
layer->OnAttach();
}
void Application::PushOverlay(Layer* layer) {
m_LayerStack.PushOverlay(layer);
layer->OnAttach();
}
}
测试:
cool!
目前代码比较潦草,甚至有些地方没有注释。计划在渲染出第一个兰伯特模型时对代码架构进行总结。