Cherno 视频:https://www.youtube.com/watch?v=rkxrw8dNrvI&list=PLlrATfBNZ98dC-V-N3m0Go4deliWHPFwT&index=32
完整代码:https://github.com/DXT00/Hazel_study/tree/80b37eba735ebbd73d9131779e0200ccaeb11267/Hazel
VertexBuffer和IndexBuffer都是实际存在于内存中的,而VertexArray 并不包含数据!
VertexArray just contain [references] to VertexBuffer and to IndexBuffer
或者说VertexArray只是链接到 VertexBuffer 和 IndexBuffer
Vertex Array are state containing entity
两种部署方式:
1.多个VertexBuffer,每个VertexBuffer一种属性(Position,Normal,Color..)
float vertices_pos[3 * 3] = {
//Position //Color
-0.5f,-0.5f,0.0f, 1.0f,0.0f,0.0f,1.0f,
0.5f,-0.5f,0.0f, 0.0f,1.0f,0.0f,1.0f,
0.0f, 0.5f,0.0f, 0.0f,0.0f,1.0f,1.0f,
};
float vertices_color[3 * 4] = {
//Color
1.0f,0.0f,0.0f,1.0f,
0.0f,1.0f,0.0f,1.0f,
0.0f,0.0f,1.0f,1.0f,
};
2.一个VertexBuffer,包含所有属性
float vertices[3 * 7] = {
//Position //Color
-0.5f,-0.5f,0.0f, 1.0f,0.0f,0.0f,1.0f,
0.5f,-0.5f,0.0f, 0.0f,1.0f,0.0f,1.0f,
0.0f, 0.5f,0.0f, 0.0f,0.0f,1.0f,1.0f,
};
you can tile together,like IndexBuffer,VertexBuffer,Layout into a VertexArray
我们采用第二种
把VertexArray抽象成类:
VertexArray.h --->抽象类,不包含任何数据
#pragma once
#include<memory>
#include "Hazel/Renderer/Buffer.h"
namespace Hazel {
class VertexArray
{
public:
virtual ~VertexArray() {};
virtual void Bind() const = 0;
virtual void UnBind() const = 0;
virtual void AddVertexBuffer(const std::shared_ptr<VertexBuffer>& vertexBufer) = 0;
virtual void SetIndexBuffer(const std::shared_ptr<IndexBuffer>& indexBuffer) = 0;
virtual const std::vector<std::shared_ptr<VertexBuffer>>& GetVertexBufers()const = 0;
virtual const std::shared_ptr<IndexBuffer>& GetIndexBuffer()const = 0;
static VertexArray *Create();
};
}
实现由 OpenGLVertexArray.h 来实现:
VertexArray是指向VertexBuffer和IndexBuffer,所以存储的只是指针!
std::vector<std::shared_ptr<VertexBuffer>> m_VertexBuffers;
std::shared_ptr<IndexBuffer> m_IndexBuffer;
#pragma once
#include "Hazel/Renderer/VertexArray.h"
#include <memory>
namespace Hazel {
class OpenGLVertexArray : public VertexArray
{
public:
OpenGLVertexArray();
virtual ~OpenGLVertexArray();
virtual void Bind() const override;
virtual void UnBind() const override;
virtual void AddVertexBuffer(const std::shared_ptr<VertexBuffer>& vertexBufer)override;
virtual void SetIndexBuffer(const std::shared_ptr<IndexBuffer>& indexBuffer) override;
virtual const std::vector<std::shared_ptr<VertexBuffer>>& GetVertexBufers()const { return m_VertexBuffers; }
virtual const std::shared_ptr<IndexBuffer>& GetIndexBuffer()const { return m_IndexBuffer; }
private:
std::vector<std::shared_ptr<VertexBuffer>> m_VertexBuffers;
std::shared_ptr<IndexBuffer> m_IndexBuffer;
uint32_t m_RendereID;
};
}
OpenGLVertexArray.cpp
#include "hzpch.h"
#include "OpenGLVertexArray.h"
#include <glad/glad.h>
namespace Hazel {
static uint32_t ShaderDataTypeToBufferType(const ShaderDataType & type) {
switch (type)
{
case ShaderDataType::Int: return GL_INT;
case ShaderDataType::Int2: return GL_INT;
case ShaderDataType::Int3: return GL_INT;
case ShaderDataType::Int4: return GL_INT;
case ShaderDataType::Float: return GL_FLOAT;
case ShaderDataType::Float2: return GL_FLOAT;
case ShaderDataType::Float3: return GL_FLOAT;
case ShaderDataType::Float4: return GL_FLOAT;
case ShaderDataType::Mat3: return GL_FLOAT;
case ShaderDataType::Mat4: return GL_FLOAT;
case ShaderDataType::False: return GL_FALSE;
case ShaderDataType::True: return GL_TRUE;
}
HZ_CORE_ASSERT(false, "Unknown ShaderDataType!")
return 0;
}
OpenGLVertexArray::OpenGLVertexArray()
{
glGenVertexArrays(1, &m_RendereID);
// glBindVertexArray(m_RendereID);
}
OpenGLVertexArray::~OpenGLVertexArray()
{
glDeleteVertexArrays(1, &m_RendereID);
}
void OpenGLVertexArray::Bind() const
{
glBindVertexArray(m_RendereID);
}
void OpenGLVertexArray::UnBind() const
{
glBindVertexArray(0);
}
void OpenGLVertexArray::AddVertexBuffer(const std::shared_ptr<VertexBuffer>& vertexBufer)
{
HZ_CORE_ASSERT(vertexBufer->GetLayout().GetElements().size(), "Vertex Buffer has no layout!!")
glBindVertexArray(m_RendereID);
vertexBufer->Bind();
uint32_t index = 0;
const auto& layout = vertexBufer->GetLayout();
for (auto& element : layout)
{
glEnableVertexAttribArray(index);
glVertexAttribPointer(index,
element.GetElementCount(),
ShaderDataTypeToBufferType(element.Type),
element.Normalized ? GL_TRUE : GL_FALSE,
layout.GetStride(),
(void *)element.Offset);
index++;
}
m_VertexBuffers.push_back(vertexBufer);
}
void OpenGLVertexArray::SetIndexBuffer(const std::shared_ptr<IndexBuffer>& indexBuffer)
{
glBindVertexArray(m_RendereID);
indexBuffer->Bind();
m_IndexBuffer = indexBuffer;
}
}
画一个方形,一个三角形:
Application.cpp
#include "hzpch.h"
#include "Application.h"
#include "Hazel/Log.h"
#include <glad/glad.h>
#include "Input.h"
#include "Platform/OpenGL/OpenGLBuffer.h"
namespace Hazel {
#define BIND_EVENT_FN(x) std::bind(&Application::x, this, std::placeholders::_1)
Application* Application::s_Instance = nullptr;
Application::Application()
{
HZ_CORE_ASSERT(!s_Instance, "Application already exists!");
s_Instance = this;
m_Window = std::unique_ptr<Window>(Window::Create());
m_Window->SetEventCallback(BIND_EVENT_FN(OnEvent));
m_ImGuiLayer = new ImGuiLayer();
PushOverLay(m_ImGuiLayer);
float vertices[3 * 7] = {
//Position //Color
-0.5f,-0.5f,0.0f, 1.0f,0.0f,0.0f,1.0f,
0.5f,-0.5f,0.0f, 0.0f,1.0f,0.0f,1.0f,
0.0f, 0.5f,0.0f, 0.0f,0.0f,1.0f,1.0f,
};
float squareVertices[3 * 4] = {
//Position //Color
-0.5f,-0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f,0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
};
unsigned int indices[3] = { 0,1,2 };
unsigned int squareIndices[6] = { 0,1,2,0,2,3 };
m_VertexArray.reset(VertexArray::Create());
m_VertexBuffer.reset(VertexBuffer::Create(vertices, sizeof(vertices)));
m_IndexBuffer.reset(IndexBuffer::Create(indices, 3));
BufferLayout layout = {
{ ShaderDataType::Float3,"a_Position", false },
{ ShaderDataType::Float4,"a_Color", false },
};
BufferLayout squareLayout = {
{ ShaderDataType::Float3,"a_Position", false },
};
m_VertexBuffer->SetLayout(layout);
m_VertexArray->AddVertexBuffer(m_VertexBuffer);
m_VertexArray->SetIndexBuffer(m_IndexBuffer);
m_SqareVA.reset(VertexArray::Create());
m_SqareVB.reset(VertexBuffer::Create(squareVertices, sizeof(squareVertices)));
m_SqareIB.reset(IndexBuffer::Create(squareIndices, 6));
m_SqareVB->SetLayout(squareLayout);
m_SqareVA->AddVertexBuffer(m_SqareVB);
m_SqareVA->SetIndexBuffer(m_SqareIB);
/* uint32_t index = 0;
for (auto& element: m_VertexBuffer->GetLayout())
{
glEnableVertexAttribArray(index);
glVertexAttribPointer(index,
element.GetElementCount(),
ShaderDataTypeToBufferType(element.Type),
element.Normalized ? GL_TRUE : GL_FALSE,
layout.GetStride(),
(void *)element.Offset);
index++;
}*/
/*glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), nullptr);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)12);
*/
const std::string vertexSrc = R"(
#version 330 core
layout(location = 0) in vec3 a_Position;
layout(location = 1) in vec4 a_Color;
out vec3 v_Position;
out vec4 v_Color;
void main()
{
v_Position = a_Position;
v_Color = a_Color;
gl_Position = vec4(a_Position,1.0);
}
)";
const std::string fragmentSrc = R"(
#version 330 core
layout(location = 0) out vec4 color;
layout(location = 1) out vec4 color1;
in vec3 v_Position;
in vec4 v_Color;
void main()
{
color = v_Color;//vec4(v_Position*0.5+0.5, 1.0);
}
)";
const std::string squareVertexSrc = R"(
#version 330 core
layout(location = 0) in vec3 a_Position;
out vec3 v_Position;
void main()
{
v_Position = a_Position;
gl_Position = vec4(a_Position,1.0);
}
)";
const std::string squareFragmentSrc = R"(
#version 330 core
layout(location = 0) out vec4 color;
in vec3 v_Position;
void main()
{
color =vec4(v_Position*0.5+0.5, 1.0);
}
)";
//m_Shader = std::make_unique<Shader>(vertexSrc,fragmentSrc);
m_Shader.reset(new Shader(vertexSrc, fragmentSrc));
m_SqareShader.reset(new Shader(squareVertexSrc, squareFragmentSrc));
}
Application::~Application()
{
}
void Application::PushLayer(Layer* layer)
{
m_LayerStack.PushLayer(layer);
layer->OnAttach();
}
void Application::PushOverLay(Layer* layer)
{
m_LayerStack.PushOverLay(layer);
layer->OnAttach();
}
void Application::OnEvent(Event& e)
{
EventDispatcher dispatcher(e);
dispatcher.Dispatch<WindowCloseEvent>(BIND_EVENT_FN(OnWindowClose));
for (auto it = m_LayerStack.end(); it != m_LayerStack.begin(); )
{
(*--it)->OnEvent(e);
if (e.Handled)
break;
}
}
void Application::Run()
{
while (m_Running)
{
glClearColor(0.1f, 0.1f, 0.1f, 1);
glClear(GL_COLOR_BUFFER_BIT);
m_SqareShader->Bind();
m_SqareVA->Bind();
glDrawElements(GL_TRIANGLES, m_SqareVA->GetIndexBuffer()->GetCount(), GL_UNSIGNED_INT, nullptr);
m_Shader->Bind();
m_VertexArray->Bind();
glDrawElements(GL_TRIANGLES, m_IndexBuffer->GetCount(), GL_UNSIGNED_INT, nullptr);
for (Layer* layer : m_LayerStack)
layer->OnUpdate();
m_ImGuiLayer->Begin();
for (Layer* layer : m_LayerStack)
layer->OnImGuiRender();
m_ImGuiLayer->End();
m_Window->OnUpdate();
}
}
bool Application::OnWindowClose(WindowCloseEvent& e)
{
m_Running = false;
return true;
}
}