본문 바로가기

게임엔진/크로스플랫폼 : HazelEngine

230429 자체 엔진 개발 : VertexArray, VertexBuffer Layout, Renderer Flow

커밋 : https://github.com/ohbumjun/GameEngineTutorial/tree/4a0a7b5c267d602a6a0531c84dc715ca8f7c5a83

 

GitHub - ohbumjun/GameEngineTutorial

Contribute to ohbumjun/GameEngineTutorial development by creating an account on GitHub.

github.com

VertexAttribute, Layout

- 쉽게 말하며 VertexBuffer 가 어떻게 구성되어 있는지를 GPU 측에 알려주는 것이다.

  해당 정보가 없이 VertexBuffer 만을 GPU가 바라본다고 할때, VertexBuffer 는 단순히 byte 의 배열에 불과하다.

  VertexAttribute, Layout 을 세팅해줌으로써 GPU 가 Vertex Buffer 를 보면서, Vertex 가 어떤 type 으로 구성되어 있는지 등을 파악할 수 있는 것이다. 

 

glEnableVertexAttribArray(index);
glVertexAttribPointer(
    index,
    element.GetComponentCount(),
    ShaderDataTypeToOpenGLBaseType(element.Type),
    element.Normalized ? GL_TRUE : GL_FALSE,
    vertexBuffer->GetLayout().GetStride(),
    (const void*)element.Offset);

 

VertexArray 

- OPENGL 에만 있는 특수 형태이다.

- 들고 있는 데이터는 1) IndexBuffer, 2) VertexBuffer 에 대한 Reference 정보이다.

- 역할 : VertexAtrribute, Layout 등의 정보와 VertexBuffer 를 연결해주는 연결고리 역할을 해준다.

 

OpenGLVertexArray::OpenGLVertexArray()
{
    glCreateVertexArrays(1, &m_RendererID);
}
void OpenGLVertexArray::Bind() const
{
    glBindVertexArray(m_RendererID);
}
void OpenGLVertexArray::Unbind() const
{
    glBindVertexArray(0);
}

 

Renderer -> RenderCommand -> RendererAPI -> Graphic API ex) OpenGL

흐름은 위와 같다고 생각하면 된다.

void Renderer::Submit
-> RenderCommand::DrawIndexed

// static RendererAPI* s_RendererAPI
-> s_RendererAPI->DrawIndexed

// 최종적으로 아래 함수 호출
void OpenGLRendererAPI::DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray)
{
    glDrawElements(GL_TRIANGLES, vertexArray->GetIndexBuffer()->GetCount(),
        GL_UNSIGNED_INT,
        nullptr);
}

 

Renderer Class 는 Render 와 관련된 로직을 담당하는 클래스이다.

따라서 아래와 같이 static 함수만을 멤버함수로 들고 있는 것을 확인할 수 있다.

enum class RendererAPI
{
    None = 0, OpenGL = 1
};

class Renderer
{
public :
    inline static RendererAPI GetAPI() { return m_RendererAPI; }

private :


    static RendererAPI m_RendererAPI;
    static void BeginScene();
    static void EndScene();
    static void Submit(const std::shared_ptr<VertexArray>& vertexArray);

    inline static RendererAPI::API GetAPI() { return RendererAPI::GetAPI(); }
};

 

RenderCommand 는 Render 와 관련된 처리를 담당하는 Command Class 이다.

중간에 이러한 Command 클래스를 둔 이유는 차후 멀티쓰레드 렌더링을 적용하기 위한 것이다. (추후 설명 예정)

class RenderCommand
{
public :
    inline static void SetClearColor(const glm::vec4& color)
    {
        s_RendererAPI->SetClearColor(color);
    }
    inline static void Clear()
    {
        s_RendererAPI->Clear();
    }
    inline static void DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray)
    {
        s_RendererAPI->DrawIndexed(vertexArray);
    }
private :
    static RendererAPI* s_RendererAPI;
};

 

RendererAPI 는 실제 Graphic API 들의 함수를 호출하기 위한, 즉, Graphic API 들을 표현하는 Base Class 이다.

class RendererAPI
{
public :
    enum class API
    {
        None = 0, OpenGL = 1
    };

public :
    virtual void SetClearColor(const glm::vec4& color) = 0;
    virtual void Clear() = 0;
    virtual void DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray) = 0;

    inline static API GetAPI() { return s_API; }

private :
    static API s_API;
};

 

해당 RendererAPI 를 상속받아 실제 내가 사용하는 Graphic API 를 적용할 수 있다.

아래의 클래는 OpenGL 을 사용하기 위해 RendererAPI 를 상속받아 작성한 Class 이다

class OpenGLRendererAPI : public RendererAPI
{
    virtual void SetClearColor(const glm::vec4& color) override;
    virtual void Clear() override;
    virtual void DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray) override;

};