EDIT: I made a sample code which replicates the problem; it should render a green quad and a red quad, however, it just renders 2 red quads. Also, even if you try to change the second quads' attributes (even like placing all 0s), it'll still just render. Somehow only the first quads' vertices are getting read and used for each subsequent quad.
C++ code:
#include <iostream> #include <fstream> #include <string> #include <sstream> #include <vector> #define GLEW_STATIC #include "GL/glew.h" #include "GLFW/glfw3.h" #include <IL/il.h> #include <IL/ilu.h> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> struct Vertex{ glm::vec2 pos, tex; glm::vec3 color; }; struct Quad{ std::vector<Vertex> vertices; glm::mat4 model; Quad(glm::vec2 pos, glm::vec2 size, const std::vector<Vertex> &v){ vertices = v; model = glm::mat4(); model = glm::translate(model, glm::vec3(pos, 0.f)); model = glm::scale(model, glm::vec3(size, 1.f)); } }; class Renderer{ private: GLuint VAO, VBO, instanceVBO, EBO; std::vector<Quad*> quads; std::vector<Vertex> vertices; std::vector<glm::mat4> models; std::vector<GLuint> indices; public: Renderer(){ /*** VAO ***/ glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); /*** Per-vertex VBO ***/ glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(0); // Position glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), nullptr); glEnableVertexAttribArray(1); // Tex Coord glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(glm::vec2))); glEnableVertexAttribArray(2); // Color glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(glm::vec2) * 2)); /*** Per-instance VBO ***/ glGenBuffers(1, &instanceVBO); glBindBuffer(GL_ARRAY_BUFFER, instanceVBO); glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(3); // Model matrix - row1 glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), nullptr); glVertexAttribDivisor(3, 1); glEnableVertexAttribArray(4); // Model matrix - row2 glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (GLvoid*)(sizeof(glm::vec4))); glVertexAttribDivisor(4, 1); glEnableVertexAttribArray(5); // Model matrix - row3 glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (GLvoid*)(sizeof(glm::vec4) * 2)); glVertexAttribDivisor(5, 1); glEnableVertexAttribArray(6); // Model matrix - row4 glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (GLvoid*)(sizeof(glm::vec4) * 3)); glVertexAttribDivisor(6, 1); /*** EBO ***/ glGenBuffers(1, &EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 0, nullptr, GL_DYNAMIC_DRAW); } ~Renderer(){ glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &instanceVBO); glDeleteBuffers(1, &EBO); glDeleteVertexArrays(1, &VAO); } void AddQuad(Quad *const quad){ quads.push_back(quad); for(unsigned int i = 0; i < 4; i++) vertices.push_back(quad->vertices[i]); models.push_back(quad->model); GLuint start = ((indices.empty()) ? 0 : indices[indices.size() - 1] + 1); GLuint newIndices[] = { start, start + 1, start + 2, start, start + 3, start + 2 }; for(unsigned int i = 0; i < 6; i++) indices.push_back(newIndices[i]); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), &vertices[0], GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, instanceVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(glm::mat4) * quads.size(), &models[0], GL_DYNAMIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), &indices[0], GL_DYNAMIC_DRAW); } void Render(GLuint &program){ glUseProgram(program); glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0, quads.size()); } void CheckQuads(){ for(unsigned int i = 0; i < quads.size(); i++) { std::cout << "Quad n." << i << "\n"; for(unsigned int j = 0; j < 4; j++) { std::cout << "\tVert " << j << ":\n"; std::cout << "\t" << quads[i]->vertices[j].pos.x << " " << quads[i]->vertices[j].pos.y << "\n"; std::cout << "\t" << quads[i]->vertices[j].tex.x << " " << quads[i]->vertices[j].tex.y << "\n"; std::cout << "\t" << quads[i]->vertices[j].color.r << " " << quads[i]->vertices[j].color.g << " " << quads[i]->vertices[j].color.b << "\n"; } } } }; GLuint GenerateShader(const std::string &filename, GLenum shaderType) { GLuint shader; std::ifstream file(filename.c_str()); std::stringstream ss; ss << file.rdbuf(); file.close(); const GLchar *source = ss.str().c_str(); shader = glCreateShader(shaderType); glShaderSource(shader, 1, &source, nullptr); glCompileShader(shader); return shader; } int main() { /*** Window + Context ***/ glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); GLFWwindow *window = glfwCreateWindow(640, 480, "OpenGL Incorrect Rendering Test", nullptr, nullptr); glfwMakeContextCurrent(window); glewExperimental = GL_TRUE; glewInit(); glViewport(0, 0, 640, 480); glClearColor(0.f, 0.f, 0.f, 1.f); glm::mat4 projection = glm::ortho(0.f, 640.f, 480.f, 0.f, -1.f, 1.f); /*** Shader Program ***/ GLuint program = glCreateProgram(); glAttachShader(program, GenerateShader("vertex_shader.glsl", GL_VERTEX_SHADER)); glAttachShader(program, GenerateShader("fragment_shader.glsl", GL_FRAGMENT_SHADER)); glLinkProgram(program); glUseProgram(program); glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, glm::value_ptr(projection)); /*** Renderer ***/ Renderer *renderer = new Renderer(); // Quad 1 Vertex v1 = {glm::vec2(0.f, 0.f), glm::vec2(0.f, 0.f), glm::vec3(1.f, 0.f, 0.f)}; Vertex v2 = {glm::vec2(1.f, 0.f), glm::vec2(0.f, 0.f), glm::vec3(1.f, 0.f, 0.f)}; Vertex v3 = {glm::vec2(1.f, 1.f), glm::vec2(0.f, 0.f), glm::vec3(1.f, 0.f, 0.f)}; Vertex v4 = {glm::vec2(0.f, 1.f), glm::vec2(0.f, 0.f), glm::vec3(1.f, 0.f, 0.f)}; renderer->AddQuad(new Quad(glm::vec2(300, 10), glm::vec2(150, 150), {v1, v2, v3, v4})); // Quad 2 Vertex v5 = {glm::vec2(0.f, 0.f), glm::vec2(0.f, 0.f), glm::vec3(0.f, 1.f, 0.f)}; Vertex v6 = {glm::vec2(1.f, 0.f), glm::vec2(0.f, 0.f), glm::vec3(0.f, 1.f, 0.f)}; Vertex v7 = {glm::vec2(1.f, 1.f), glm::vec2(0.f, 0.f), glm::vec3(0.f, 1.f, 0.f)}; Vertex v8 = {glm::vec2(0.f, 1.f), glm::vec2(0.f, 0.f), glm::vec3(0.f, 1.f, 0.f)}; renderer->AddQuad(new Quad(glm::vec2(30, 10), glm::vec2(150, 150), {v5, v6, v7, v8})); while(!glfwWindowShouldClose(window)) { glfwPollEvents(); if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); glClear(GL_COLOR_BUFFER_BIT); renderer->Render(program); glfwSwapBuffers(window); } delete renderer; glfwDestroyWindow(window); glfwTerminate(); return 0; }
vertex_shader.glsl:
#version 430 core layout (location = 0) in vec2 position; layout (location = 1) in vec2 texCoord; layout (location = 2) in vec3 color; layout (location = 3) in mat4 model; out vec2 uv; out vec3 col; uniform mat4 projection; void main() { uv = texCoord; col = color; gl_Position = projection * model * vec4(position, 0.f, 1.f); }
fragment_shader.glsl:
#version 430 core in vec2 uv; in vec3 col; out vec4 color; void main() { color = vec4(col, 1.f); }