Hazel游戏引擎(030)顶点与索引缓冲的抽象

文中若有代码、术语等错误,欢迎指正

前言

  • 此节目的

    对于OpenGL的生成顶点缓冲索引缓冲这种原始代码抽象成类。

    Application里面有创建opengl的渲染代码,顶点缓冲、索引缓冲,想要application中不含这些OpenGL函数,就需要将这些操作封装成类。

  • 如何设计类

    从想使用的API形式出发

    VertexBuffer m_VertexBuffer = new VertexBuffer(vertices, sizeof(vertices));
    // 在m_VertexArray构造函数中完成创建顶点缓冲对象、绑定、与从CPU数据发送到GPU上
    
  • 渲染接口的设计

    由于可以有多个渲染图形API:OpenGL、DX,若引擎支持两种渲染图形API,需要设计选择哪一个

    • 如果是在编译时确定选择

      缺点:如果更改渲染对象,需要重新编译引擎、且运行时不能切换

    • 如果是在运行时确定选择

      缺点:编译时两个渲染相关obj都要编译

      优点:能动态切换

      如何实现:采用C++的动态特性,基类指针指向子类对象实现动态多态

  • 运行时确定渲染接口的类图:以顶点缓冲对象、索引缓冲对象为例

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vA7nSyro-1687801459944)(null)]

    解读:

    如:VertexBuffer有静态Create函数,返回VertexBuffer*,根据选择不同渲染图形API调用return new OpenGLVertexBuffer还是DirectxVertexBuffer,基类指针指向子类对象,C++的动态多态。(但后面的章节会使用宏定义在编译时就确定了选择哪个渲染图形API)

项目相关

代码增加与修改

  • Application

    	private:
    		std::unique_ptr<Window> m_Window;
    		ImGuiLayer* m_ImGuiLayer;
    		bool m_Running = true;
    		LayerStack m_LayerStack;
    
    		unsigned int m_VertexArray;
    		std::unique_ptr<Shader> m_Shader;
    		std::unique_ptr<VertexBuffer> m_VertexBuffer;
    		std::unique_ptr<IndexBuffer> m_IndexBuffer;
    
    ......
    // 使用OpenGL函数渲染一个三角形
    // 顶点数据
    float vertices[3 * 3] = {
          
          
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f,  0.5f, 0.0f
    };
    unsigned int indices[3] = {
          
           0, 1, 2 }; // 索引数据
    
    // 0.生成顶点数组对象VAO、顶点缓冲对象VBO、索引缓冲对象EBO/
    glGenVertexArrays(1, &m_VertexArray);
    // 1. 绑定顶点数组对象
    glBindVertexArray(m_VertexArray);
    
    // 2.1顶点缓冲
    m_VertexBuffer.reset(VertexBuffer::Create(vertices, sizeof(vertices)));// 在这里
    
    // 2.2 设定顶点属性指针,来解释顶点缓冲中的顶点属性布局
    glEnableVertexAttribArray(0);// 开启glsl的layout = 0输入
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
    
    // 3.索引缓冲
    m_IndexBuffer.reset(IndexBuffer::Create(indices, sizeof(indices) / sizeof(uint32_t)));// 在这里
    ......
    
  • Renderer

    #pragma once
    namespace Hazel {
          
          
    	enum class RendererAPI
    	{
          
          
    		None = 0, OpenGL = 1
    	};
    	class Renderer{
          
          
    	public:
    		inline static RendererAPI GetAPI() {
          
           return s_RendererAPI; }
    	private:
    		static RendererAPI s_RendererAPI;
    	};
    }
    
    #include "hzpch.h"
    #include "Renderer.h"
    namespace Hazel {
          
          
    	RendererAPI Renderer::s_RendererAPI = RendererAPI::OpenGL;
    }
    
  • 增加VertexBuffer与IndexBuffer类同放在Buffer文件中

    #pragma once
    namespace Hazel {
          
          
    	class VertexBuffer{
          
          
    	public:
    		virtual ~VertexBuffer(){
          
          }
    		virtual void Bind() const = 0;
    		virtual void Unbind() 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;
    		virtual uint32_t GetCount() const = 0;
    		static IndexBuffer* Create(uint32_t* indices, uint32_t size);
    	};
    }		
    
    #include "hzpch.h"
    #include "Buffer.h"
    // 根据不同平台而创建不同的。。。
    #include "Renderer.h"
    #include "Platform/OpenGL/OpenGLBuffer.h"
    namespace Hazel {
          
          
    	VertexBuffer* VertexBuffer::Create(float* vertices, uint32_t size){
          
          
    		switch (Renderer::GetAPI()) {
          
          
    			case RendererAPI::None: HZ_CORE_ASSERT(false, "RendererAPI:None is currently not supported!"); return nullptr;
    			case RendererAPI::OpenGL: return new OpenGLVertexBuffer(vertices, size);
    		}
    		HZ_CORE_ASSERT(false, "Unknown RendererAPI!");
    		return nullptr;
    	}
    	IndexBuffer* IndexBuffer::Create(uint32_t* indices, uint32_t size){
          
          
    		switch (Renderer::GetAPI()) {
          
          
    			case RendererAPI::None: HZ_CORE_ASSERT(false, "RendererAPI:None is currently not supported!"); return nullptr;
    			case RendererAPI::OpenGL: return new OpenGLIndexBuffer(indices, size);
    		}
    		HZ_CORE_ASSERT(false, "Unknown RendererAPI!");
    		return nullptr;
    	}
    }
    
  • OpenGLBuffer

    #pragma once
    #include "Hazel/Renderer/Buffer.h"
    namespace Hazel {
          
          
    	class OpenGLVertexBuffer : public VertexBuffer{
          
          
    	public:
    		OpenGLVertexBuffer(float* vertices, uint32_t size);
    		virtual ~OpenGLVertexBuffer();
    
    		virtual void Bind() const;
    		virtual void Unbind() const;
    	private:
    		uint32_t m_RendererID;
    	};
    	class OpenGLIndexBuffer : public IndexBuffer{
          
          
    	public:
    		OpenGLIndexBuffer(uint32_t* indices, uint32_t count);
    		virtual ~OpenGLIndexBuffer();
    		virtual void Bind() const;
    		virtual void Unbind() const;
    		virtual uint32_t GetCount() const {
          
           return m_Count; }
    	private:
    		uint32_t m_RendererID;
    		uint32_t m_Count;
    	};
    }
    
    #include "hzpch.h"
    #include "OpenGLBuffer.h"
    #include <glad/glad.h>
    namespace Hazel {
          
          
    	// VertexBuffer /
    	OpenGLVertexBuffer::OpenGLVertexBuffer(float* vertices, uint32_t size){
          
          
    		// 1.创建顶点缓冲对象
    		glCreateBuffers(1, &m_RendererID);
    		// 2.绑定顶点缓冲对象
    		glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
    		// 3. 把我们的CPU的顶点数据复制到GPU顶点缓冲中,供OpenGL使用
    		glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_STATIC_DRAW);
    	}
    	OpenGLVertexBuffer::~OpenGLVertexBuffer(){
          
          
    		glDeleteBuffers(1, &m_RendererID);
    	}
    	void OpenGLVertexBuffer::Bind() const{
          
          
    		glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
    	}
    	void OpenGLVertexBuffer::Unbind() const{
          
          
    		glBindBuffer(GL_ARRAY_BUFFER, 0);
    	}
    	// IndexBuffer //
    	OpenGLIndexBuffer::OpenGLIndexBuffer(uint32_t* indices, uint32_t count)
    		: m_Count(count){
          
          		
    		// 1.创建顶点缓冲对象
    		glCreateBuffers(1, &m_RendererID);
    		// 2.绑定顶点缓冲对象
    		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
    		// 3. 复制我们的CPU的索引数据到GPU索引缓冲中,供OpenGL使用
    		glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(uint32_t), indices, GL_STATIC_DRAW);
    	}
    	OpenGLIndexBuffer::~OpenGLIndexBuffer(){
          
          
    		glDeleteBuffers(1, &m_RendererID);
    	}
    	void OpenGLIndexBuffer::Bind() const{
          
          
    		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
    	}
    	void OpenGLIndexBuffer::Unbind() const{
          
          
    		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    	}
    }
    

效果

不变,证明抽象顶点缓冲、索引缓冲类成功

请添加图片描述

猜你喜欢

转载自blog.csdn.net/qq_34060370/article/details/131408341
今日推荐