【7】集成vao vbo

在之前的代码中,生成、绑定顶点数组对象,生成、绑定顶点缓冲对象,启用顶点属性数组,写了很长一部分,很麻烦。因此集成为类。

主义理清vao与vbo之间的关系

    VertexArray va; 
    VertexBuffer vb(positions, 4 * 2 * sizeof(float));
   
    VertexBufferLayout layout; 
    layout.Push<float>(2);// layout主要是数据的格式
    va.AddBuffer(vb, layout); 

分析一下代码,va是顶点数组 vertex array object,vb是顶点缓冲对象 vertex buffer object 。positions是顶点数组,存有二维顶点数据,共有四个点,用来绘制矩形。

先抛开layout不谈。

VertexArray声明

#pragma once

#include "VertexBuffer.h"
#include "VertexBufferLayout.h"

class VertexArray
{
private:
	unsigned int m_RendererID;
public:
	VertexArray();
	~VertexArray();

	void AddBuffer(const VertexBuffer& vb, const VertexBufferLayout& layout);

	void Bind() const;
	void UnBind() const;
};

定义

#include "VertexArray.h"
#include "Renderer.h"

VertexArray::VertexArray()
{
	/* generate vertex array object names,指定个数1,存储名字到m_RendererID */
	GLCall(glGenVertexArrays(1, &m_RendererID));
}

VertexArray::~VertexArray()
{
	GLCall(glDeleteVertexArrays(1, &m_RendererID)); 
}

void VertexArray::AddBuffer(const VertexBuffer& vb, const VertexBufferLayout& layout)
{
	Bind();/*绑定到当前vao*/
	vb.Bind();/*绑定vbo。绑定顶点缓冲区*/
	const auto& elements = layout.GetElements(); /*设置布局*/
	unsigned int offset = 0;
	for (unsigned int i = 0; i < elements.size(); i++)
	{
		const auto& element = elements[i];
		GLCall(glEnableVertexAttribArray(i));/* 0位置, 1颜色*/
		/*例如:0-位置,2-二维;1-颜色,4-rgbx四个属性确定一个颜色
		stride-数据步长,pointer-指针指向当前index对应的起始偏移量*/
		GLCall(glVertexAttribPointer(i, element.count, element.type,
			element.normalized , layout.GetStride(), (const void*)offset));/* (const void)*/
		// offset += element.count;
		offset += element.count * VertexBufferElement::GetSizeOfType(element.type);
	}
	
}

void VertexArray::Bind() const
{
	/*参数array
Specifies the name of the vertex array to bind.*/
	GLCall(glBindVertexArray(m_RendererID));
}

void VertexArray::UnBind() const
{
	GLCall(glBindVertexArray(0));

}


可以看到,初始化时生成了 vao,并存储了名字到 m_RendererID

VertexArray::VertexArray()
{
	/* generate vertex array object names,指定个数1,存储名字到m_RendererID */
	GLCall(glGenVertexArrays(1, &m_RendererID));
}

后面使用时还需要绑定,因此在函数AddBuffer中先调用 Bind:

Bind();/*绑定到当前vao*/
void VertexArray::Bind() const
{
	/*参数array
Specifies the name of the vertex array to bind.*/
	GLCall(glBindVertexArray(m_RendererID));
}

对于 vbo 同样的,初始化函数里生成并存储名字,接着使用前需要绑定:vb.Bind();/*绑定vbo。绑定顶点缓冲区*/

现在绑定好了vao vbo,接着就是启用顶点数组 glEnableVertexAttribArray ,接着规定数据格式 glVertexAttribPointer

主要是这几句:

	for (unsigned int i = 0; i < elements.size(); i++)
	{
		const auto& element = elements[i];
		GLCall(glEnableVertexAttribArray(i));/* 0位置, 1颜色*/
		/*例如:0-位置,2-二维;1-颜色,4-rgbx四个属性确定一个颜色
		stride-数据步长,pointer-指针指向当前index对应的起始偏移量*/
		GLCall(glVertexAttribPointer(i, element.count, element.type,
			element.normalized , layout.GetStride(), (const void*)offset));/* (const void)*/
		// offset += element.count;
		offset += element.count * VertexBufferElement::GetSizeOfType(element.type);
	}

根据 glVertexAttribPointer 的参数,我们就可以分析出 layout 的作用。


VertexBufferLayout.h

#pragma once
#include 
#include 
#include 
#include "Renderer.h"
/*如果你不想因为使用一小部分glew的功能而引入 glew.h
可以进入定义,查看例如 GL_FLOAT的 定义,把你需要的部分 define 粘贴过来*/

struct VertexBufferElement
{
	unsigned int type;
	unsigned int count;
	// bool normalized;
	unsigned char normalized;
	
	static unsigned int GetSizeOfType(unsigned int type)
	{
		switch (type)
		{
		case GL_FLOAT: return 4;
		case GL_UNSIGNED_INT: return 4;
		case GL_UNSIGNED_BYTE: return 1; 
		}
		ASSERT(false);
		return 0;
	}
};

class VertexBufferLayout
{
private:
	std::vector<VertexBufferElement> m_Elements;
	unsigned int m_Stride;
public:
	VertexBufferLayout()
		: m_Stride(0) {};

	template<typename T>  
	void Push(unsigned int count)
	{/*
@lichform
1年前
If you're on VS2022 and having an issue with the static_assert getting tripped in the 
unspecialized template, it's because VS2022 will trigger the assert when it's parsed,
rather than when it's instantiated. I changed it to a std::runtime_error which of course 
isn't checked at compile time but at least I get a verbose error when I try to create a 
VertexBufferLayout with an unsupported type.


@dr_nyt4041
1年前
Thanks, that helped!
#include 

template
void Push(unsigned int count) {
	std::runtime_error(false);
}*/
		// static_assert(false);/*不知道为什么弹出这里的错误提示 ?*/ 
		std::runtime_error(false);
	}

	template<>
	void Push<float>(unsigned int count)
	{
		m_Elements.push_back({ GL_FLOAT, count, GL_FALSE }); 
		// m_Stride += 4; /* sizeof(float) */
		// m_Stride += sizeof(GLfloat);
		m_Stride += count * VertexBufferElement::GetSizeOfType(GL_FLOAT);
	}

	template<>
	void Push<unsigned int>(unsigned int count)
	{
		m_Elements.push_back({ GL_UNSIGNED_INT, count, GL_FALSE });
		// m_Stride += sizeof(GLuint);
		m_Stride += count * VertexBufferElement::GetSizeOfType(GL_UNSIGNED_INT);
	}

	template<>
	void Push<unsigned char>(unsigned int count)
	{
		m_Elements.push_back({ GL_UNSIGNED_BYTE, count, GL_TRUE });
		// m_Stride += sizeof(GLbyte);
		m_Stride += count * VertexBufferElement::GetSizeOfType(GL_UNSIGNED_BYTE);
	}

	//inline const std::vector GetElements() const { return m_Elements; }
	//inline unsigined int GetStride() const { return m_Stride; }

	inline const std::vector<VertexBufferElement>& GetElements() const {
		return m_Elements;
	}

	inline unsigned int GetStride() const {
		return m_Stride;
	}
};


总的代码:
仓库地址

你可能感兴趣的:(openGL,c++)