Cherno 视频:https://www.youtube.com/watch?v=jIJFM_pi6gQ&list=PLlrATfBNZ98dC-V-N3m0Go4deliWHPFwT&index=31
完整代码:https://github.com/DXT00/Hazel_study/tree/e129b773d1feb24e44b73bd4967471d886dcf025
注意 BufferLayout是对VertexBuffer来说的,即对vertex属性的设置(如Position,Color)
所以,我们在VertexBuffer中添加Layout接口:
virtual void SetLayout(const BufferLayout& layout) = 0;
virtual const BufferLayout& GetLayout() const= 0;
原Application.cpp中的Vertex Buffer Layouts :
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);
可以看到vertex array包含两个Layout,分别对应shader里的a_Position,a_Color
float vertices[3 * 7] = {
//a_Position //a_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,};
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] = {
-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,
};
unsigned int indices[3] = { 0,1,2 };
glGenVertexArrays(1, &m_VertexArray);
glBindVertexArray(m_VertexArray);
m_VertexBuffer.reset(VertexBuffer::Create(vertices, sizeof(vertices)));
m_IndexBuffer.reset(IndexBuffer::Create(indices, 3));
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);
}
)";
//m_Shader = std::make_unique<Shader>(vertexSrc,fragmentSrc);
m_Shader.reset(new Shader(vertexSrc, fragmentSrc));
}
F5运行:
现在我们需要把VertexLayout封装成更加好的可读易用的形式:
如:
BufferLayout layout = {
{ ShaderDataType::Float3,"a_Position"},
{ ShaderDataType::Float4,"a_Color" },
{ ShaderDataType::Float4,"a_TextCord" },
}
对应:
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);
在Bufer.h中添加Layout:
#pragma once
#include <vector>
#include<unordered_map>
namespace Hazel {
enum class ShaderDataType {
Int,
Int2,
Int3,
Int4,
Float,
Float2,
Float3,
Float4,
Mat3,
Mat4,
False,
True,
};
static uint32_t GetTypeSize(ShaderDataType& type)
{
switch (type)
{
case ShaderDataType::Int: return 1 * sizeof(int);
case ShaderDataType::Int2: return 2 * sizeof(int);
case ShaderDataType::Int3: return 3 * sizeof(int);
case ShaderDataType::Int4: return 4 * sizeof(int);
case ShaderDataType::Float: return 1 * sizeof(float);
case ShaderDataType::Float2: return 2 * sizeof(float);
case ShaderDataType::Float3: return 3 * sizeof(float);
case ShaderDataType::Float4: return 4 * sizeof(float);
case ShaderDataType::Mat3: return 3 * 3 * sizeof(float);
case ShaderDataType::Mat4: return 4 * 4 * sizeof(float);
case ShaderDataType::False: return 1;
case ShaderDataType::True: return 1;
}
HZ_CORE_ASSERT(false, "Unknown ShaderDataType!")
return 0;
}
struct BufferElement
{
ShaderDataType Type;
std::string Name;
bool Normalized;
uint32_t Offset;
uint32_t Size;//一层layout的总字节数 (Int3 --> 3*sizeof(int))
BufferElement(ShaderDataType type, std::string name, bool normalized) :
Type(type), Name(name), Normalized(normalized), Offset(0), Size(GetTypeSize(type)) {}
uint32_t GetElementCount() const{
switch (Type)
{
case ShaderDataType::Int: return 1;
case ShaderDataType::Int2: return 2;
case ShaderDataType::Int3: return 3;
case ShaderDataType::Int4: return 4;
case ShaderDataType::Float: return 1;
case ShaderDataType::Float2: return 2;
case ShaderDataType::Float3: return 3;
case ShaderDataType::Float4: return 4;
case ShaderDataType::Mat3: return 3 * 3;
case ShaderDataType::Mat4: return 4 * 4;
case ShaderDataType::False: return 1;
case ShaderDataType::True: return 1;
}
}
};
class BufferLayout {
public:
BufferLayout() {}
BufferLayout(const std::initializer_list<BufferElement> elements)
:m_Elements(elements) {
CalculateStrideAndOffset();
}
inline const std::vector<BufferElement> &GetElements() const { return m_Elements; }
std::vector<BufferElement>::iterator begin() { return m_Elements.begin(); }
std::vector<BufferElement>::iterator end() { return m_Elements.end(); }
inline uint32_t GetStride() const { return m_Stride; };
const void CalculateStrideAndOffset() {
m_Stride = 0;
int offset = 0;
for (BufferElement &element : m_Elements) {
m_Stride += element.Size;
element.Offset = offset;
offset += m_Stride;
}
};
private:
std::vector<BufferElement> m_Elements;
uint32_t m_Stride = 0;
};
//只是抽象类,不存任何数据
class VertexBuffer {
public:
virtual ~VertexBuffer() {};
virtual void Bind() const = 0;
virtual void UnBind() const = 0;
virtual void SetLayout(const BufferLayout& layout) = 0;
virtual const BufferLayout& GetLayout() const = 0;
static VertexBuffer *Create(float *vertices, uint32_t size);
};
class IndexBuffer {
public:
virtual ~IndexBuffer() {};
virtual void Bind() const = 0;
virtual void UnBind() const = 0;
static IndexBuffer *Create(uint32_t *Indices, uint32_t count);
virtual uint32_t GetCount() const = 0;
};
}
Applicatioin.cpp设置Layout:
BufferLayout layout = {
{ ShaderDataType::Float3,"a_Position", false },
{ ShaderDataType::Float4,"a_Color", false },
};
uint32_t index = 0;
for (auto& element: layout)
{
glEnableVertexAttribArray(index);
glVertexAttribPointer(index,
element.GetElementCount(),
ShaderDataTypeToBufferType(element.Type),
element.Normalized ? GL_TRUE : GL_FALSE,
layout.GetStride(),
(void *)element.Offset);
in
这里有个错误:
由于 GetLayout返回的element列表是const的,所以我们需要使用 const_iterater
virtual const BufferLayout& GetLayout() const= 0;
class BufferLayout {
public:
BufferLayout() {}
BufferLayout(const std::initializer_list<BufferElement> elements)
:m_Elements(elements) {
CalculateStrideAndOffset();
}
inline const std::vector<BufferElement> &GetElements() const { return m_Elements; }
std::vector<BufferElement>::iterator begin() { return m_Elements.begin(); }
std::vector<BufferElement>::iterator end() { return m_Elements.end(); }
std::vector<BufferElement>::const_iterator begin() const { return m_Elements.begin(); }
std::vector<BufferElement>::const_iterator end() const { return m_Elements.end(); }
inline uint32_t GetStride() const { return m_Stride; };
const void CalculateStrideAndOffset() {
m_Stride = 0;
int offset = 0;
for (BufferElement &element : m_Elements) {
m_Stride += element.Size;
element.Offset = offset;
offset += m_Stride;
}
};
private:
std::vector<BufferElement> m_Elements;
uint32_t m_Stride = 0;
};