OpenGL批处理渲染器在清除颜色后显示空白窗口,且没有OpenGL错误

编程语言 2026-07-09

我正在做一个项目,想实现一个批处理渲染器。

我尝试开启调试模式,但没有收到任何OpenGL信息,更别说错误信息了。我也尝试使用 RenderDoc 在程序运行时对其进行检查,但没有成功,因为我对RenderDoc中程序应该的样子不是很熟悉。就我从Visual Studio调试器看到的情况来看,我的顶点似乎被正确打包,我调用的任何函数都没有返回OpenGL错误。

这是我的代码库;它可以运行并显示一个蓝色窗口。它应该显示这个窗口以及屏幕中央的一个红色矩形,但我没有看到那个矩形。

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>

#include <string>
#include <memory>
#include <fstream>
#include <sstream>
#include <iostream>
#include <array>


//////////////////
// BEGIN SHADER //
//////////////////

class Shader
{
public:
    Shader();
    ~Shader();

    void use();

    void setUniformMat4(const std::string name, glm::mat4 value);

private:
    uint32_t m_rendererID;
};

Shader::Shader()
{

    const char* vShaderCode = R"END(
        #version 450 core

        layout(location = 0) in vec3 a_Position;
        layout(location = 1) in vec4 a_Color;
        layout(location = 2) in vec2 a_TexCoord;
        layout(location = 3) in float a_TexIndex;
        layout(location = 4) in float a_TilingFactor;

        uniform mat4 u_ViewProjection;

        struct VertexOutput
        {
            vec4 Color;
            vec2 TexCoord;
            float TexIndex;
            float TilingFactor;
        };

        layout (location = 0) out VertexOutput Output;

        void main()
        {
            Output.Color = a_Color;
            Output.TexCoord = a_TexCoord;
            Output.TexIndex = a_TexIndex;
            Output.TilingFactor = a_TilingFactor;

            gl_Position = u_ViewProjection * vec4(a_Position, 1.0);
        }
    )END";
    const char* fShaderCode = R"END(
        #version 450 core

        layout(location = 0) out vec4 color;

        struct VertexOutput
        {
            vec4 Color;
            vec2 TexCoord;
            float TexIndex;
            float TilingFactor;
        };

        layout (location = 0) in VertexOutput Input;

        layout (binding = 0) uniform sampler2D u_Textures[32];

        void main()
        {
            vec4 texColor = Input.Color;

            switch(int(Input.TexIndex))
            {
                case  0: texColor *= texture(u_Textures[ 0], Input.TexCoord * Input.TilingFactor); break;
                case  1: texColor *= texture(u_Textures[ 1], Input.TexCoord * Input.TilingFactor); break;
                case  2: texColor *= texture(u_Textures[ 2], Input.TexCoord * Input.TilingFactor); break;
                case  3: texColor *= texture(u_Textures[ 3], Input.TexCoord * Input.TilingFactor); break;
                case  4: texColor *= texture(u_Textures[ 4], Input.TexCoord * Input.TilingFactor); break;
                case  5: texColor *= texture(u_Textures[ 5], Input.TexCoord * Input.TilingFactor); break;
                case  6: texColor *= texture(u_Textures[ 6], Input.TexCoord * Input.TilingFactor); break;
                case  7: texColor *= texture(u_Textures[ 7], Input.TexCoord * Input.TilingFactor); break;
                case  8: texColor *= texture(u_Textures[ 8], Input.TexCoord * Input.TilingFactor); break;
                case  9: texColor *= texture(u_Textures[ 9], Input.TexCoord * Input.TilingFactor); break;
                case 10: texColor *= texture(u_Textures[10], Input.TexCoord * Input.TilingFactor); break;
                case 11: texColor *= texture(u_Textures[11], Input.TexCoord * Input.TilingFactor); break;
                case 12: texColor *= texture(u_Textures[12], Input.TexCoord * Input.TilingFactor); break;
                case 13: texColor *= texture(u_Textures[13], Input.TexCoord * Input.TilingFactor); break;
                case 14: texColor *= texture(u_Textures[14], Input.TexCoord * Input.TilingFactor); break;
                case 15: texColor *= texture(u_Textures[15], Input.TexCoord * Input.TilingFactor); break;
                case 16: texColor *= texture(u_Textures[16], Input.TexCoord * Input.TilingFactor); break;
                case 17: texColor *= texture(u_Textures[17], Input.TexCoord * Input.TilingFactor); break;
                case 18: texColor *= texture(u_Textures[18], Input.TexCoord * Input.TilingFactor); break;
                case 19: texColor *= texture(u_Textures[19], Input.TexCoord * Input.TilingFactor); break;
                case 20: texColor *= texture(u_Textures[20], Input.TexCoord * Input.TilingFactor); break;
                case 21: texColor *= texture(u_Textures[21], Input.TexCoord * Input.TilingFactor); break;
                case 22: texColor *= texture(u_Textures[22], Input.TexCoord * Input.TilingFactor); break;
                case 23: texColor *= texture(u_Textures[23], Input.TexCoord * Input.TilingFactor); break;
                case 24: texColor *= texture(u_Textures[24], Input.TexCoord * Input.TilingFactor); break;
                case 25: texColor *= texture(u_Textures[25], Input.TexCoord * Input.TilingFactor); break;
                case 26: texColor *= texture(u_Textures[26], Input.TexCoord * Input.TilingFactor); break;
                case 27: texColor *= texture(u_Textures[27], Input.TexCoord * Input.TilingFactor); break;
                case 28: texColor *= texture(u_Textures[28], Input.TexCoord * Input.TilingFactor); break;
                case 29: texColor *= texture(u_Textures[29], Input.TexCoord * Input.TilingFactor); break;
                case 30: texColor *= texture(u_Textures[30], Input.TexCoord * Input.TilingFactor); break;
                case 31: texColor *= texture(u_Textures[31], Input.TexCoord * Input.TilingFactor); break;
            }
            color = texColor;
        }
    )END";

    unsigned int vertex, fragment;

    vertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex, 1, &vShaderCode, NULL);
    glCompileShader(vertex);

    fragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment, 1, &fShaderCode, NULL);
    glCompileShader(fragment);

    m_rendererID = glCreateProgram();
    glAttachShader(m_rendererID, vertex);
    glAttachShader(m_rendererID, fragment);
    glLinkProgram(m_rendererID);

    glDeleteShader(vertex);
    glDeleteShader(fragment);
}

Shader::~Shader()
{
    glDeleteProgram(m_rendererID);
}

void Shader::use()
{
    glUseProgram(m_rendererID);
}

void Shader::setUniformMat4(const std::string name, glm::mat4 value)
{
    glUniformMatrix4fv(glGetUniformLocation(m_rendererID, name.c_str()), 1, GL_FALSE, glm::value_ptr(value));
}

///////////////////
// BEGIN TEXTURE //
///////////////////

class Texture
{
public:
    Texture(uint32_t width, uint32_t height);
    ~Texture();

    uint32_t getWidth() const { return m_width; }
    uint32_t getHeight() const { return m_height; }

    void setData(void* data, uint32_t size);

    void bind(uint32_t slot = 0) const;

    bool operator==(const Texture& other) const
    {
        return m_rendererID == ((Texture&)other).m_rendererID;
    }

private:
    std::string m_path;
    uint32_t m_width, m_height;
    uint32_t m_rendererID;
    GLenum m_internalFormat, m_dataFormat;
};

Texture::Texture(uint32_t width, uint32_t height)
    : m_width(width), m_height(height)
{
    m_internalFormat = GL_RGBA8;
    m_dataFormat = GL_RGBA;

    glCreateTextures(GL_TEXTURE_2D, 1, &m_rendererID);
    glTextureStorage2D(m_rendererID, 1, m_internalFormat, m_width, m_height);

    glTextureParameteri(m_rendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTextureParameteri(m_rendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glTextureParameteri(m_rendererID, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTextureParameteri(m_rendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);
}

Texture::~Texture()
{
    glDeleteTextures(1, &m_rendererID);
}

void Texture::setData(void* data, uint32_t size)
{
    uint32_t bpp = m_dataFormat == GL_RGBA ? 4 : 3;
    glTextureSubImage2D(m_rendererID, 0, 0, 0, m_width, m_height, m_dataFormat, GL_UNSIGNED_BYTE, data);
}

void Texture::bind(uint32_t slot) const
{
    glBindTextureUnit(slot, m_rendererID);
}

//////////
// CODE //
//////////

const uint32_t RendererMaxQuads = 10000;
const uint32_t RendererMaxIndices = 6 * RendererMaxQuads;
const uint32_t RendererMaxVertexCount = 4 * RendererMaxQuads;
const uint32_t RendererMaxTextureSlots = 32;

struct Vertex {
    glm::vec3 Position;
    glm::vec4 Color;
    glm::vec2 TexCoord;
    float TexIndex;
    float TilingFactor;

    Vertex()
    {
        Position = { 0, 0, 0 };
        Color = { 0,0,0,1 };
        TexCoord = { 0, 0 };
        TexIndex = 0;
        TilingFactor = 1;
    }

    Vertex(glm::vec3 pos, glm::vec4 color, glm::vec2 texCoord, float texIndex, float tilingFactor)
    {
        Position = pos;
        Color = color;
        TexCoord = texCoord;
        TexIndex = texIndex;
        TilingFactor = tilingFactor;
    }
};

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

Shader* TextureShader = nullptr;
Texture* WhiteTexture = nullptr;
std::array<Texture*, RendererMaxTextureSlots> TextureSlots;
std::array<Vertex, RendererMaxVertexCount> Verticies;

GLuint VAO = 0;
GLuint VBO = 0;
GLuint IndexBuffer = 0;

uint32_t VertexCount = 0;
uint32_t IndexCount = 0;
uint32_t TextureSlotIndex = 0;

void Flush()
{
    if (VertexCount == 0)
    {
        // Nothing to draw
        return;
    }

    TextureShader->use();
    TextureShader->setUniformMat4("u_ViewProjection", glm::ortho(0, 800, 0, 600, -1, 1));

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferSubData(GL_ARRAY_BUFFER, 0, VertexCount * sizeof(Vertex), &Verticies);

    // Bind textures
    for (uint32_t i = 0; i < TextureSlotIndex; i++)
        TextureSlots[i]->bind(i);

    glDrawElements(GL_TRIANGLES, IndexCount, GL_UNSIGNED_INT, nullptr);
}

void DrawQuad(glm::vec3 position, glm::vec2 size, glm::vec4 color)
{
    if (VertexCount >= RendererMaxVertexCount - 4)
    {
        Flush();
        VertexCount = 0;
        IndexCount = 0;
        TextureSlotIndex = 1; // 0 = WhiteTexture
    }

    // Add verticies
    Verticies[VertexCount++] = {
        position + glm::vec3(size.x, size.y, 0.0f), // Top Right
        color,
        {1, 1}, // Top Right
        0, // White Texture
        1 // No Tiling
    };
    Verticies[VertexCount++] = {
        position + glm::vec3(-size.x, size.y, 0.0f), // Top Left
        color,
        {0, 1}, // Top Left
        0, // White Texture
        1 // No Tiling
    };
    Verticies[VertexCount++] = {
        position + glm::vec3(size.x, -size.y, 0.0f), // Bottom Right
        color,
        {1, 0}, // Bottom Right
        0, // White Texture
        1 // No Tiling
    };
    Verticies[VertexCount++] = {
        position + glm::vec3(-size.x, -size.y, 0.0f), // Bottom Left
        color,
        {0, 0}, // Bottom Left
        0, // White Texture
        1 // No Tiling
    };
}

int main()
{
    // Start OpenGL context and OS window using the GLFW helper library.
    if (!glfwInit()) {
        std::cout << "ERROR: could not start GLFW" << std::endl;
        return -1;
    }

    // Request an OpenGL 4.5, core, context from GLFW.
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // Create a window on the operating system, then tie the OpenGL context to it.
    GLFWwindow* Window = glfwCreateWindow(800, 600, "windowTitle", NULL, NULL);
    if (!Window) {
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(Window);
    glfwSetFramebufferSizeCallback(Window, framebuffer_size_callback);

    // Start Glad, so we can call OpenGL functions.
    if (gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) == 0) {
        return -1;
    }

    glEnable(GL_DEPTH_TEST);

    glCreateVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glCreateBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * RendererMaxVertexCount, NULL, GL_DYNAMIC_DRAW);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::Position));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::Color));
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::TexCoord));
    glEnableVertexAttribArray(3);
    glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::TexIndex));
    glEnableVertexAttribArray(4);
    glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::TilingFactor));

    TextureShader = new Shader();

    WhiteTexture = new Texture(1, 1);
    uint32_t whiteTextureData = 0xffffffff;
    WhiteTexture->setData(&whiteTextureData, sizeof(uint32_t));
    TextureSlots[0] = WhiteTexture;

    uint32_t* quadIndices = new uint32_t[RendererMaxIndices];
    uint32_t offset = 0;
    for (uint32_t i = 0; i < RendererMaxIndices; i += 6)
    {
        quadIndices[i + 0] = offset + 0;
        quadIndices[i + 1] = offset + 2;
        quadIndices[i + 2] = offset + 1;

        quadIndices[i + 3] = offset + 1;
        quadIndices[i + 4] = offset + 2;
        quadIndices[i + 5] = offset + 3;

        offset += 4;
    }

    glCreateBuffers(1, &IndexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, IndexBuffer);
    glBufferData(GL_ARRAY_BUFFER, RendererMaxIndices * sizeof(uint32_t), quadIndices, GL_STATIC_DRAW);

    delete[] quadIndices;

    glClearColor( 0.0f, 0.0f, 1.0f, 1.0f);


    while (!glfwWindowShouldClose(Window))
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        VertexCount = 0;
        IndexCount = 0;
        TextureSlotIndex = 1; // 0 = WhiteTexture

        DrawQuad({ 0.0f, 0.0f, 0.0f}, { 1.0f, 1.0f }, { 1, 0, 0, 1 });

        Flush();

        glfwSwapBuffers(Window);
        glfwPollEvents();
    }

    delete TextureShader;
    delete WhiteTexture;
    glfwTerminate();
    return 0;
}

我尝试了各种修复方法:确保所有三角形的索引顺序正确,确保着色器不仅是在渲染一个透明纹理,确保我要渲染的顶点确实在相机的视野内,结果都无济于事。如果你恰好弄清楚我哪里做错了,请告诉我是怎么发现的。

解决方案

代码里有几个问题:

  1. 我从不增加IndexCount,因此当待绘制的索引数量为零时,绘制调用显然不会绘制任何东西。
  2. 在创建索引缓冲区时,我对glBindBuffer和 glBufferData传入的参数是GL_ARRAY_BUFFER,而不是正确的GL_ELEMENT_ARRAY_BUFFER。
  3. 最后,当我调用glm::ortho() 为场景创建投影矩阵时,我指定了一个800×600的窗口,将设备坐标从左下角的0,0映射到右上角的800,600。因此,当我在0,0处渲染一个大小为 (1,1) 的对象时,它渲染得太小,以致于在屏幕角落几乎看不到。

解决了所有这些问题后,我得到了期望的输出。

最终代码:

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>

#include <string>
#include <memory>
#include <fstream>
#include <sstream>
#include <iostream>
#include <array>


//////////////////
// BEGIN SHADER //
//////////////////

class Shader
{
public:
    Shader();
    ~Shader();

    void use();

    void setUniformMat4(const std::string name, glm::mat4 value);

private:
    uint32_t m_rendererID;
};

Shader::Shader()
{

    const char* vShaderCode = R"END(
        #version 450 core

        layout(location = 0) in vec3 a_Position;
        layout(location = 1) in vec4 a_Color;
        layout(location = 2) in vec2 a_TexCoord;
        layout(location = 3) in float a_TexIndex;
        layout(location = 4) in float a_TilingFactor;

        uniform mat4 u_ViewProjection;

        struct VertexOutput
        {
            vec4 Color;
            vec2 TexCoord;
            float TexIndex;
            float TilingFactor;
        };

        layout (location = 0) out VertexOutput Output;

        void main()
        {
            Output.Color = a_Color;
            Output.TexCoord = a_TexCoord;
            Output.TexIndex = a_TexIndex;
            Output.TilingFactor = a_TilingFactor;

            gl_Position = vec4(a_Position, 1.0);
        }
    )END";
    const char* fShaderCode = R"END(
        #version 450 core

        layout(location = 0) out vec4 color;

        struct VertexOutput
        {
            vec4 Color;
            vec2 TexCoord;
            float TexIndex;
            float TilingFactor;
        };

        layout (location = 0) in VertexOutput Input;

        layout (binding = 0) uniform sampler2D u_Textures[32];

        void main()
        {
            vec4 texColor = Input.Color;

            switch(int(Input.TexIndex))
            {
                case  0: texColor *= texture(u_Textures[ 0], Input.TexCoord * Input.TilingFactor); break;
                case  1: texColor *= texture(u_Textures[ 1], Input.TexCoord * Input.TilingFactor); break;
                case  2: texColor *= texture(u_Textures[ 2], Input.TexCoord * Input.TilingFactor); break;
                case  3: texColor *= texture(u_Textures[ 3], Input.TexCoord * Input.TilingFactor); break;
                case  4: texColor *= texture(u_Textures[ 4], Input.TexCoord * Input.TilingFactor); break;
                case  5: texColor *= texture(u_Textures[ 5], Input.TexCoord * Input.TilingFactor); break;
                case  6: texColor *= texture(u_Textures[ 6], Input.TexCoord * Input.TilingFactor); break;
                case  7: texColor *= texture(u_Textures[ 7], Input.TexCoord * Input.TilingFactor); break;
                case  8: texColor *= texture(u_Textures[ 8], Input.TexCoord * Input.TilingFactor); break;
                case  9: texColor *= texture(u_Textures[ 9], Input.TexCoord * Input.TilingFactor); break;
                case 10: texColor *= texture(u_Textures[10], Input.TexCoord * Input.TilingFactor); break;
                case 11: texColor *= texture(u_Textures[11], Input.TexCoord * Input.TilingFactor); break;
                case 12: texColor *= texture(u_Textures[12], Input.TexCoord * Input.TilingFactor); break;
                case 13: texColor *= texture(u_Textures[13], Input.TexCoord * Input.TilingFactor); break;
                case 14: texColor *= texture(u_Textures[14], Input.TexCoord * Input.TilingFactor); break;
                case 15: texColor *= texture(u_Textures[15], Input.TexCoord * Input.TilingFactor); break;
                case 16: texColor *= texture(u_Textures[16], Input.TexCoord * Input.TilingFactor); break;
                case 17: texColor *= texture(u_Textures[17], Input.TexCoord * Input.TilingFactor); break;
                case 18: texColor *= texture(u_Textures[18], Input.TexCoord * Input.TilingFactor); break;
                case 19: texColor *= texture(u_Textures[19], Input.TexCoord * Input.TilingFactor); break;
                case 20: texColor *= texture(u_Textures[20], Input.TexCoord * Input.TilingFactor); break;
                case 21: texColor *= texture(u_Textures[21], Input.TexCoord * Input.TilingFactor); break;
                case 22: texColor *= texture(u_Textures[22], Input.TexCoord * Input.TilingFactor); break;
                case 23: texColor *= texture(u_Textures[23], Input.TexCoord * Input.TilingFactor); break;
                case 24: texColor *= texture(u_Textures[24], Input.TexCoord * Input.TilingFactor); break;
                case 25: texColor *= texture(u_Textures[25], Input.TexCoord * Input.TilingFactor); break;
                case 26: texColor *= texture(u_Textures[26], Input.TexCoord * Input.TilingFactor); break;
                case 27: texColor *= texture(u_Textures[27], Input.TexCoord * Input.TilingFactor); break;
                case 28: texColor *= texture(u_Textures[28], Input.TexCoord * Input.TilingFactor); break;
                case 29: texColor *= texture(u_Textures[29], Input.TexCoord * Input.TilingFactor); break;
                case 30: texColor *= texture(u_Textures[30], Input.TexCoord * Input.TilingFactor); break;
                case 31: texColor *= texture(u_Textures[31], Input.TexCoord * Input.TilingFactor); break;
            }
            color = texColor;
        }
    )END";

    unsigned int vertex, fragment;

    vertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex, 1, &vShaderCode, NULL);
    glCompileShader(vertex);

    fragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment, 1, &fShaderCode, NULL);
    glCompileShader(fragment);

    m_rendererID = glCreateProgram();
    glAttachShader(m_rendererID, vertex);
    glAttachShader(m_rendererID, fragment);
    glLinkProgram(m_rendererID);

    glDeleteShader(vertex);
    glDeleteShader(fragment);
}

Shader::~Shader()
{
    glDeleteProgram(m_rendererID);
}

void Shader::use()
{
    glUseProgram(m_rendererID);
}

void Shader::setUniformMat4(const std::string name, glm::mat4 value)
{
    glUniformMatrix4fv(glGetUniformLocation(m_rendererID, name.c_str()), 1, GL_FALSE, glm::value_ptr(value));
}

///////////////////
// BEGIN TEXTURE //
///////////////////

class Texture
{
public:
    Texture(uint32_t width, uint32_t height);
    ~Texture();

    uint32_t getWidth() const { return m_width; }
    uint32_t getHeight() const { return m_height; }

    void setData(void* data, uint32_t size);

    void bind(uint32_t slot = 0) const;

    bool operator==(const Texture& other) const
    {
        return m_rendererID == ((Texture&)other).m_rendererID;
    }

private:
    std::string m_path;
    uint32_t m_width, m_height;
    uint32_t m_rendererID;
    GLenum m_internalFormat, m_dataFormat;
};

Texture::Texture(uint32_t width, uint32_t height)
    : m_width(width), m_height(height)
{
    m_internalFormat = GL_RGBA8;
    m_dataFormat = GL_RGBA;

    glCreateTextures(GL_TEXTURE_2D, 1, &m_rendererID);
    glTextureStorage2D(m_rendererID, 1, m_internalFormat, m_width, m_height);

    glTextureParameteri(m_rendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTextureParameteri(m_rendererID, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    glTextureParameteri(m_rendererID, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTextureParameteri(m_rendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);
}

Texture::~Texture()
{
    glDeleteTextures(1, &m_rendererID);
}

void Texture::setData(void* data, uint32_t size)
{
    uint32_t bpp = m_dataFormat == GL_RGBA ? 4 : 3;
    glTextureSubImage2D(m_rendererID, 0, 0, 0, m_width, m_height, m_dataFormat, GL_UNSIGNED_BYTE, data);
}

void Texture::bind(uint32_t slot) const
{
    glBindTextureUnit(slot, m_rendererID);
}

//////////
// CODE //
//////////

const uint32_t RendererMaxQuads = 10000;
const uint32_t RendererMaxIndices = 6 * RendererMaxQuads;
const uint32_t RendererMaxVertexCount = 4 * RendererMaxQuads;
const uint32_t RendererMaxTextureSlots = 32;

struct Vertex {
    glm::vec3 Position;
    glm::vec4 Color;
    glm::vec2 TexCoord;
    float TexIndex;
    float TilingFactor;

    Vertex()
    {
        Position = { 0, 0, 0 };
        Color = { 0,0,0,1 };
        TexCoord = { 0, 0 };
        TexIndex = 0;
        TilingFactor = 1;
    }

    Vertex(glm::vec3 pos, glm::vec4 color, glm::vec2 texCoord, float texIndex, float tilingFactor)
    {
        Position = pos;
        Color = color;
        TexCoord = texCoord;
        TexIndex = texIndex;
        TilingFactor = tilingFactor;
    }
};

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

Shader* TextureShader = nullptr;
Texture* WhiteTexture = nullptr;
std::array<Texture*, RendererMaxTextureSlots> TextureSlots;
std::array<Vertex, RendererMaxVertexCount> Verticies;

GLuint VAO = 0;
GLuint VBO = 0;
GLuint IndexBuffer = 0;

uint32_t VertexCount = 0;
uint32_t IndexCount = 0;
uint32_t TextureSlotIndex = 0;

void Flush()
{
    if (VertexCount == 0)
    {
        // Nothing to draw
        return;
    }

    TextureShader->use();

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferSubData(GL_ARRAY_BUFFER, 0, VertexCount * sizeof(Vertex), &Verticies);

    // Bind textures
    for (uint32_t i = 0; i < TextureSlotIndex; i++)
        TextureSlots[i]->bind(i);

    glDrawElements(GL_TRIANGLES, IndexCount, GL_UNSIGNED_INT, nullptr);
}

void DrawQuad(glm::vec3 position, glm::vec2 size, glm::vec4 color)
{
    if (VertexCount >= RendererMaxVertexCount - 4)
    {
        Flush();
        VertexCount = 0;
        IndexCount = 0;
        TextureSlotIndex = 1; // 0 = WhiteTexture
    }

    // Add verticies
    Verticies[VertexCount++] = {
        position + glm::vec3(size.x, size.y, 0.0f), // Top Right
        color,
        {1, 1}, // Top Right
        0, // White Texture
        1 // No Tiling
    };
    Verticies[VertexCount++] = {
        position + glm::vec3(-size.x, size.y, 0.0f), // Top Left
        color,
        {0, 1}, // Top Left
        0, // White Texture
        1 // No Tiling
    };
    Verticies[VertexCount++] = {
        position + glm::vec3(size.x, -size.y, 0.0f), // Bottom Right
        color,
        {1, 0}, // Bottom Right
        0, // White Texture
        1 // No Tiling
    };
    Verticies[VertexCount++] = {
        position + glm::vec3(-size.x, -size.y, 0.0f), // Bottom Left
        color,
        {0, 0}, // Bottom Left
        0, // White Texture
        1 // No Tiling
    };

    IndexCount += 6;
}

int main()
{
    // Start OpenGL context and OS window using the GLFW helper library.
    if (!glfwInit()) {
        std::cout << "ERROR: could not start GLFW" << std::endl;
        return -1;
    }

    // Request an OpenGL 4.5, core, context from GLFW.
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // Create a window on the operating system, then tie the OpenGL context to it.
    GLFWwindow* Window = glfwCreateWindow(800, 600, "windowTitle", NULL, NULL);
    if (!Window) {
        glfwTerminate();
        return -1;
    }
    glfwMakeContextCurrent(Window);
    glfwSetFramebufferSizeCallback(Window, framebuffer_size_callback);

    // Start Glad, so we can call OpenGL functions.
    if (gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) == 0) {
        return -1;
    }

    glEnable(GL_DEPTH_TEST);

    glCreateVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glCreateBuffers(1, &VBO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * RendererMaxVertexCount, NULL, GL_DYNAMIC_DRAW);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::Position));
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::Color));
    glEnableVertexAttribArray(2);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::TexCoord));
    glEnableVertexAttribArray(3);
    glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::TexIndex));
    glEnableVertexAttribArray(4);
    glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, Vertex::TilingFactor));

    TextureShader = new Shader();

    WhiteTexture = new Texture(1, 1);
    uint32_t whiteTextureData = 0xffffffff;
    WhiteTexture->setData(&whiteTextureData, sizeof(uint32_t));
    TextureSlots[0] = WhiteTexture;

    uint32_t* quadIndices = new uint32_t[RendererMaxIndices];
    uint32_t offset = 0;
    for (uint32_t i = 0; i < RendererMaxIndices; i += 6)
    {
        quadIndices[i + 0] = offset + 0;
        quadIndices[i + 1] = offset + 2;
        quadIndices[i + 2] = offset + 1;

        quadIndices[i + 3] = offset + 1;
        quadIndices[i + 4] = offset + 2;
        quadIndices[i + 5] = offset + 3;

        offset += 4;
    }

    glCreateBuffers(1, &IndexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, RendererMaxIndices * sizeof(uint32_t), quadIndices, GL_STATIC_DRAW);

    delete[] quadIndices;

    glClearColor( 0.0f, 0.0f, 1.0f, 1.0f);


    while (!glfwWindowShouldClose(Window))
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        VertexCount = 0;
        IndexCount = 0;
        TextureSlotIndex = 1; // 0 = WhiteTexture

        DrawQuad({ 0, 0, 0.0f}, { 0.5f, 0.5f }, { 1, 0, 0, 1 });

        Flush();

        glfwSwapBuffers(Window);
        glfwPollEvents();
    }

    delete TextureShader;
    delete WhiteTexture;
    glfwTerminate();
    return 0;
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章