ARTICLE AD BOX
I'm working on a project that I'd like to implement a batch renderer for.
I've tried enabling debug mode and have not been receiving any OpenGL messages let alone errors. I've tried using RenderDoc to inspect the program while it is running with no luck as I'm somewhat unfamiliar with what the program should look like in RenderDoc. As far as I can tell looking at the visual studio debugger my vertices are being correctly packed and I'm not getting any OpenGL errors from any of the functions I'm calling.
Here is my codebase; it runs and displays a blue colored window. It should display that along with a red rectangle in the center of the screen, but I see no such rectangle.
#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; }I've tried various fixes: making sure all my triangles are indexed in the correct order, making sure the shaders aren't just rendering a transparent texture, making sure the vertices I'm trying to render are actually in view of the camera, all to no avail. If you happen to figure out what I have done wrong, let me know how you figured it out.
