2021SC@SDUSC
目录
1.1VertexBuffer.h与VertexBuffer.inl
1.1.1VertexBuffer(T* p_data, size_t p_elements)
1.1.2VertexBuffer(std::vector& p_data)
1.2VertexArray.h与VertexArray.inl
2.1.1Framebuffer(uint16_t p_width, uint16_t p_height)
2.1.2 Resize(uint16_t p_width, uint16_t p_height)
本章继续讨论OvRendering中的函数。本章主要讨论顶点着色器与片段着色器的相关函数。
1.Vertex相关数据结构
在讨论此节之前,建议将这三个单词先记下来:
- 顶点数组对象:Vertex Array Object,VAO
- 顶点缓冲对象:Vertex Buffer Object,VBO
- 索引缓冲对象:Element Buffer Object,EBO或Index Buffer Object,IBO
本文所讨论的函数将会调用大量OpenGL相关API,关于OpenGL的相关知识可访问链接LearnOpenGL CN
1.1VertexBuffer.h与VertexBuffer.inl
在一个物体的定义顶点数据以后,我们会把它作为输入发送给图形渲染管线的第一个处理阶段:顶点着色器。它会在GPU上创建内存用于储存我们的顶点数据,还要配置OpenGL如何解释这些内存,并且指定其如何发送给显卡。顶点着色器接着会处理我们在内存中指定数量的顶点。
我们通过顶点缓冲对象(Vertex Buffer Objects, VBO)管理这个内存,它会在GPU内存(通常被称为显存)中储存大量顶点。使用这些缓冲对象的好处是我们可以一次性的发送一大批数据到显卡上,而不是每个顶点发送一次。从CPU把数据发送到显卡相对较慢,所以只要可能我们都要尝试尽量一次性发送尽可能多的数据。
namespace OvRendering::Buffers
{
template <class T>
class VertexBuffer
{
public:
VertexBuffer(T* p_data, size_t p_elements);
VertexBuffer(std::vector<T>& p_data);
~VertexBuffer();
void Bind();
void Unbind();
uint32_t GetID();
private:
uint32_t m_bufferID;
};
}
#include "OvRendering/Buffers/VertexBuffer.inl"
而VertexBuffer使用内联文件来实现函数体,接下来我们来看具体的函数。
1.1.1VertexBuffer(T* p_data, size_t p_elements)
template <class T>
inline VertexBuffer<T>::VertexBuffer(T* p_data, size_t p_elements)
{
glGenBuffers(1, &m_bufferID);
glBindBuffer(GL_ARRAY_BUFFER, m_bufferID);
glBufferData(GL_ARRAY_BUFFER, p_elements * sizeof(T), p_data, GL_STATIC_DRAW);
}
VertexBuffer函数用于实现VBO与顶点数据的绑定,其中调用了3个OpenGL的API。
顶点缓冲对象是OpenGL的一个对象。就像OpenGL中的其它对象一样,这个缓冲有一个独一无二的ID,即类中的私有变量m_bufferID,所以我们可以使用glGenBuffers函数和一个缓冲ID生成一个VBO对象。
glGenBuffers(1, &m_bufferID);
OpenGL有很多缓冲对象类型,顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER。OpenGL允许我们同时绑定多个缓冲,只要它们是不同的缓冲类型。我们可以使用glBindBuffer函数把新创建的缓冲绑定到GL_ARRAY_BUFFER目标上。
glBindBuffer(GL_ARRAY_BUFFER, m_bufferID);
从这一刻起,我们使用的任何(在GL_ARRAY_BUFFER目标上的)缓冲调用都会用来配置当前绑定的缓冲(VBO)。然后我们可以调用glBufferData函数,它会把之前定义的顶点数据复制到缓冲的内存中:
glBufferData(GL_ARRAY_BUFFER, p_elements * sizeof(T), p_data, GL_STATIC_DRAW);
glBufferData是一个专门用来把用户定义的数据复制到当前绑定缓冲的函数。它的第一个参数是目标缓冲的类型:顶点缓冲对象当前绑定到GL_ARRAY_BUFFER目标上。第二个参数指定传输数据的大小(以字节为单位);用一个简单的sizeof
计算出顶点数据大小就行。第三个参数是我们希望发送的实际数据。
第四个参数指定了我们希望显卡如何管理给定的数据。它有三种形式:
- GL_STATIC_DRAW :数据不会或几乎不会改变。
- GL_DYNAMIC_DRAW:数据会被改变很多。
- GL_STREAM_DRAW :数据每次绘制时都会改变。
1.1.2VertexBuffer(std::vector<T>& p_data)
在讲这个函数前要先了解EBO的概念。
在渲染过程中物体是有多边形网格构成的,每个网格都有若干的顶点,每渲染一个网格就需要所有顶点的信息。如果使用VBO,就需要将所有网格的顶点全部存储进内存,这当中存在大量的重复顶点,造成了资源的浪费。
所以当重复顶点数量过大时,我们可以使用索引缓冲对象(Element Buffer Object,EBO,也叫Index Buffer Object,IBO),来处理不同三角面片的重复的顶点。简单的原理就是将所有顶点存入一个集合&