Guest User

Instanced rendering with ARB_vertex_attrib_binding

a guest
Jul 25th, 2015
285
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <GL/glew.h>
  2. #include <SDL2/SDL.h>
  3. #include <glm/glm.hpp>
  4. #include <glm/gtc/matrix_transform.hpp>
  5. #include <cstdio>
  6.  
  7. #define SKIP 1
  8.  
  9. inline void glError(const char *file, int line) {
  10.     GLenum err;
  11.     while((err = glGetError()) != GL_NO_ERROR){
  12.         char error[128];
  13.  
  14.         switch(err) {
  15.             case GL_INVALID_ENUM:                   snprintf(error, sizeof(error), "%s", "INVALID_ENUM");                   break;
  16.             case GL_INVALID_VALUE:                  snprintf(error, sizeof(error), "%s", "INVALID_VALUE");                  break;
  17.             case GL_INVALID_OPERATION:              snprintf(error, sizeof(error), "%s", "INVALID_OPERATION");              break;
  18.             case GL_OUT_OF_MEMORY:                  snprintf(error, sizeof(error), "%s", "OUT_OF_MEMORY");                  break;
  19.             case GL_INVALID_FRAMEBUFFER_OPERATION:  snprintf(error, sizeof(error), "%s", "INVALID_FRAMEBUFFER_OPERATION");  break;
  20.             default:                                snprintf(error, sizeof(error), "%s", "UNKNOWN_ERROR");                  break;
  21.         }
  22.  
  23.         fprintf(stderr, "GL%s - %s: %d\n", error, file, line);
  24.     }
  25. }
  26.  
  27. static inline void validateShader(GLuint shader){
  28.     const unsigned int BUFFER_SIZE = 512;
  29.     char buffer[BUFFER_SIZE];
  30.     //memset(buffer, 0, BUFFER_SIZE);
  31.     GLsizei length = 0;
  32.    
  33.     glGetShaderInfoLog(shader, BUFFER_SIZE, &length, buffer);
  34.    
  35.     if(length>0){
  36.         printf("Shader %d compile error: %s\n", shader, buffer);
  37.     }
  38. }
  39.  
  40. static inline bool validateProgram(GLuint program){
  41.     const GLsizei BUFFER_SIZE = 512;
  42.     GLchar buffer[BUFFER_SIZE];
  43.     memset(buffer, 0, BUFFER_SIZE);
  44.     GLsizei length = 0;
  45.    
  46.     glGetProgramInfoLog(program, BUFFER_SIZE, &length, buffer);
  47.    
  48.     if(length>0){
  49.         printf("Program %d link error: %s\n", program, buffer);
  50.     }
  51.    
  52.     glValidateProgram(program);
  53.     GLint status;
  54.     glGetProgramiv(program, GL_VALIDATE_STATUS, &status);
  55.    
  56.     if(status == GL_FALSE){
  57.         printf("Error validating program %d.\n", program);
  58.         return false;
  59.     }
  60.     return true;
  61. }
  62.  
  63. struct Vertex{
  64.     glm::vec3 p, n;
  65. };
  66.  
  67. static const glm::vec3 vs[] = {
  68.     glm::vec3( 1.0, -1.0, -1.0),
  69.     glm::vec3( 1.0, -1.0,  1.0),
  70.     glm::vec3(-1.0, -1.0,  1.0),
  71.     glm::vec3(-1.0, -1.0, -1.0),
  72.     glm::vec3( 1.0,  1.0, -1.0),
  73.     glm::vec3( 1.0,  1.0,  1.0),
  74.     glm::vec3(-1.0,  1.0,  1.0),
  75.     glm::vec3(-1.0,  1.0, -1.0)
  76. };
  77.  
  78. static const glm::vec3 ns[] = {
  79.     glm::vec3( 0.0, -1.0,  0.0),
  80.     glm::vec3( 0.0,  1.0,  0.0),
  81.     glm::vec3( 1.0,  0.0,  0.0),
  82.     glm::vec3( 0.0,  0.0,  1.0),
  83.     glm::vec3(-1.0,  0.0,  0.0),
  84.     glm::vec3( 0.0,  0.0, -1.0)
  85. };
  86.  
  87. static const Vertex cube_vertices[] = {
  88.     Vertex{vs[0], ns[0]}, Vertex{vs[1], ns[0]}, Vertex{vs[2], ns[0]},
  89.     Vertex{vs[0], ns[0]}, Vertex{vs[2], ns[0]}, Vertex{vs[3], ns[0]},
  90.     Vertex{vs[4], ns[1]}, Vertex{vs[7], ns[1]}, Vertex{vs[6], ns[1]},
  91.     Vertex{vs[4], ns[1]}, Vertex{vs[6], ns[1]}, Vertex{vs[5], ns[1]},
  92.     Vertex{vs[0], ns[2]}, Vertex{vs[4], ns[2]}, Vertex{vs[5], ns[2]},
  93.     Vertex{vs[0], ns[2]}, Vertex{vs[5], ns[2]}, Vertex{vs[1], ns[2]},
  94.     Vertex{vs[1], ns[3]}, Vertex{vs[5], ns[3]}, Vertex{vs[6], ns[3]},
  95.     Vertex{vs[1], ns[3]}, Vertex{vs[6], ns[3]}, Vertex{vs[2], ns[3]},
  96.     Vertex{vs[2], ns[4]}, Vertex{vs[6], ns[4]}, Vertex{vs[7], ns[4]},
  97.     Vertex{vs[2], ns[4]}, Vertex{vs[7], ns[4]}, Vertex{vs[3], ns[4]},
  98.     Vertex{vs[4], ns[5]}, Vertex{vs[0], ns[5]}, Vertex{vs[3], ns[5]},
  99.     Vertex{vs[4], ns[5]}, Vertex{vs[3], ns[5]}, Vertex{vs[7], ns[5]}
  100. };
  101.  
  102. int main(int argc, char* argv[]){
  103.  
  104.     if(SDL_Init(SDL_INIT_VIDEO) < 0){
  105.         SDL_Quit();
  106.         return 0;
  107.     }
  108.  
  109.     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
  110.     SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
  111.  
  112.     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  113.     SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
  114.  
  115.     SDL_Window* window = SDL_CreateWindow(
  116.         "test",
  117.         SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
  118.         600, 600,
  119.         SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
  120.     );
  121.  
  122.     if(!window){
  123.         SDL_Quit();
  124.         return 0;
  125.     }
  126.  
  127.     SDL_GLContext context = SDL_GL_CreateContext(window);
  128.  
  129.     glewExperimental = GL_TRUE;
  130.     GLenum err = glewInit();
  131.     if(GLEW_OK != err){
  132.         SDL_Quit();
  133.         return 0;
  134.     }
  135.     glError(__FILE__, __LINE__);
  136.  
  137.     SDL_GL_SetSwapInterval(1);
  138.  
  139.     //--Setup model matrices
  140.     int n_instances = 4096;
  141.     glm::mat4 modelMatrices[n_instances];
  142.     for(int i = 0, idx = 0; i < 16; ++i){
  143.         for(int j = 0; j < 16; ++j){
  144.             for(int k = 0; k < 16; ++k, ++idx){
  145.                 modelMatrices[idx] = glm::translate(
  146.                     glm::mat4(1.0), 2.2f * glm::vec3(i, j, -k) - 1.1f * 16.0f * glm::vec3(1.0, 1.0, -1.0)
  147.                 );
  148.             }
  149.         }
  150.     }
  151.  
  152.     //--Upload cube vertices
  153.     GLuint cube_vbo;
  154.     glGenBuffers(1, &cube_vbo);
  155.     glBindBuffer(GL_ARRAY_BUFFER, cube_vbo);
  156.     glBufferData(GL_ARRAY_BUFFER, 12 * 3 * sizeof(Vertex), cube_vertices, GL_STATIC_DRAW);
  157.  
  158.     //--Upload model matrix
  159.     GLuint mm_vbo;
  160.     glGenBuffers(1, &mm_vbo);
  161.     glBindBuffer(GL_ARRAY_BUFFER, mm_vbo);
  162.     glBufferData(GL_ARRAY_BUFFER, n_instances * sizeof(glm::mat4), modelMatrices, GL_STATIC_DRAW);
  163.  
  164.     //--Setup vertex format
  165.     GLuint vao;
  166.     glGenVertexArrays(1, &vao);
  167.     glBindVertexArray(vao);
  168.  
  169.     int va_idx = 0;
  170.  
  171.     glEnableVertexAttribArray(va_idx);
  172.     glVertexAttribFormat(va_idx, 3, GL_FLOAT, GL_FALSE, 0);
  173.     glVertexAttribBinding(va_idx, 0);
  174.     ++va_idx;
  175. #if SKIP == 1
  176.     ++va_idx;
  177. #endif
  178.    
  179.     glEnableVertexAttribArray(va_idx);
  180.     glVertexAttribFormat(va_idx, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3));
  181.     glVertexAttribBinding(va_idx, 0);
  182.     ++va_idx;
  183.  
  184.     for(int i = 0; i < 4; i++){ //Model Matrices
  185.         glEnableVertexAttribArray(va_idx);
  186.         glVertexAttribFormat(va_idx, 4, GL_FLOAT, GL_FALSE, sizeof(float) * i * 4);
  187.         glVertexAttribBinding(va_idx, 1);
  188.         ++va_idx;
  189.     }
  190.     glVertexAttribDivisor(1, 1);
  191.  
  192.     glBindVertexArray(0);
  193.  
  194.     //--Setup shaders
  195.     GLuint shader;
  196.     GLint loc_projectionMatrix, loc_mvMatrix;
  197.     {
  198.         const char* vs_source =
  199.             "#version 330 core\n"
  200.             "layout(location = 0) in vec3 in_position;\n"
  201. #if SKIP == 1
  202.             "layout(location = 2) in vec3 in_normal;\n"
  203.             "layout(location = 3) in mat4 modelMatrix;\n"
  204. #else
  205.             "layout(location = 1) in vec3 in_normal;\n"
  206.             "layout(location = 2) in mat4 modelMatrix;\n"
  207. #endif
  208.             "uniform mat4 projectionMatrix;\n"
  209.             "uniform mat4 mvMatrix;\n"
  210.             "smooth out vec3 normal;\n"
  211.             "void main(void){\n"
  212.             "    normal = mat3(transpose(inverse(mvMatrix * modelMatrix))) * in_normal;\n"
  213.             "    gl_Position = projectionMatrix * mvMatrix * modelMatrix * vec4(in_position, 1.0);\n"
  214.            "}\n";
  215.  
  216.         GLuint vs = glCreateShader(GL_VERTEX_SHADER);
  217.         glShaderSource(vs, 1, &vs_source, 0);
  218.         glCompileShader(vs);
  219.         validateShader(vs);
  220.  
  221.         const char* fs_source =
  222.             "#version 330 core\n"
  223.             "smooth in vec3 normal;\n"
  224.             "layout(location = 0) out vec4 color;\n"
  225.             "void main(void){\n"
  226.             "   color = vec4(normal, 1.0);\n"
  227.             "}\n";
  228.  
  229.         GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
  230.         glShaderSource(fs, 1, &fs_source, 0);
  231.         glCompileShader(fs);
  232.         validateShader(fs);
  233.  
  234.         shader = glCreateProgram();
  235.         glAttachShader(shader, vs);
  236.         glAttachShader(shader, fs);
  237.         glLinkProgram(shader);
  238.  
  239.         glDetachShader(shader, vs);
  240.         glDetachShader(shader, fs);
  241.         glDeleteShader(vs);
  242.         glDeleteShader(fs);
  243.  
  244.         if(!validateProgram(shader)){
  245.             glDeleteBuffers(1, &cube_vbo);
  246.             glDeleteVertexArrays(1, &vao);
  247.             glDeleteProgram(shader);
  248.  
  249.             SDL_GL_DeleteContext(context);
  250.             SDL_DestroyWindow(window);
  251.             SDL_Quit();
  252.  
  253.             return 0;
  254.         }
  255.  
  256.         loc_projectionMatrix = glGetUniformLocation(shader, "projectionMatrix");
  257.         loc_mvMatrix = glGetUniformLocation(shader, "mvMatrix");
  258.     }
  259.  
  260.     glm::mat4 projectionMatrix = glm::perspective(glm::radians(60.0), 1.0, 10.0, 300.0);
  261.     glm::mat4 viewMatrix = glm::lookAt(glm::vec3(0.0, 0.0, 80.0), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
  262.  
  263.     //--Setup uniforms
  264.     glUseProgram(shader);
  265.     {
  266.         glUniformMatrix4fv(loc_projectionMatrix, 1, GL_FALSE, &projectionMatrix[0][0]);
  267.         glUniformMatrix4fv(loc_mvMatrix, 1, GL_FALSE, &viewMatrix[0][0]);
  268.     }
  269.     glUseProgram(0);
  270.  
  271.     bool quit = false;
  272.     SDL_Event event;
  273.  
  274.     glClearColor(0.0, 0.0, 0.0, 1.0);
  275.     glViewport(0, 0, 600, 600);
  276.     glEnable(GL_CULL_FACE);
  277.     glCullFace(GL_BACK);
  278.     glEnable(GL_DEPTH_TEST);
  279.  
  280.     glBindVertexArray(vao);
  281.     glm::mat4 mvMatrix = viewMatrix;
  282.     while(!quit){
  283.         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  284.  
  285.         glUseProgram(shader);
  286.  
  287.         mvMatrix = glm::rotate(mvMatrix, glm::radians(0.4f), glm::vec3(0.0, 1.0, 1.0));
  288.         glUniformMatrix4fv(loc_mvMatrix, 1, GL_FALSE, &mvMatrix[0][0]);
  289.  
  290.         glBindVertexBuffer(0, cube_vbo, 0, sizeof(Vertex));
  291.         glBindVertexBuffer(1, mm_vbo, 0, sizeof(glm::mat4));
  292.  
  293.         glDrawArraysInstanced(GL_TRIANGLES, 0, 12 * 3, n_instances);
  294.  
  295.         glUseProgram(0);
  296.  
  297.         while(SDL_PollEvent(&event) != 0){
  298.             if(event.type == SDL_QUIT) quit = true;
  299.         }
  300.  
  301.         SDL_GL_SwapWindow(window);
  302.     }
  303.     glBindVertexArray(0);
  304.  
  305.     glDeleteBuffers(1, &cube_vbo);
  306.     glDeleteVertexArrays(1, &vao);
  307.  
  308.     SDL_GL_DeleteContext(context);
  309.     SDL_DestroyWindow(window);
  310.     SDL_Quit();
  311.  
  312.  
  313.     return 0;
  314. }
RAW Paste Data