Haxel Engine learning 16 -- Vertex Buffer Layouts

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;


	};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值