3/17

3. Affichage d’un triangle

L’étape suivante consiste à utiliser les fonctions OpenGL pour afficher une forme 3D sur la fenêtre. Nous considérons dans cet exemple minimaliste l’affichage d’un immobile possédant une couleur uniforme.

Le code correspondant à l’affichage d’objets en OpenGL peut généralement être catégorisé en trois étapes

  • Étape d’initialisation

    • Mise en place des shaders (1)

    • Envoie des données sur la carte graphique (2)

  • Demande d’affichage des données (3) (Correspond à l’exécution du Pipe-Line Graphique)

Les deux premières étapes d’initialisation ne sont exécutées qu’une seule fois et peuvent être réalisées dans l’ordre souhaité, alors que la demande d’affichage est réalisée dans la boucle d’animation et nécessite les deux étapes précédentes.


A titre d’information, le code complet de la fonction d’affichage d’un triangle est visible ci-dessous. La suite du tutoriel détaille ses différentes sous-parties.

triangle

[ code, main.cpp ]

#include <glad/glad.hpp>
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>



int main()
{
    std::cout<<"*** Init GLFW ***"<<std::endl;
    const int glfw_init_value = glfwInit();
    if( glfw_init_value != GLFW_TRUE ) {
        std::cerr<<"Failed to Init GLFW"<<std::endl;
        abort();
    }


    std::cout<<"*** Create window ***"<<std::endl;
    const int window_width  = 500;
    const int window_height = 500;
    const std::string title = "My Window";

    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);
    glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1);
    glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* window = glfwCreateWindow(window_width, window_height, title.c_str(), /*monitor*/ nullptr, /*share*/ nullptr);
    if( window==nullptr ) {
        std::cerr<<"Failed to create GLFW Window"<<std::endl;
        abort();
    }

    glfwMakeContextCurrent(window);

    std::cout<<"*** Init GLAD ***"<<std::endl;
    const int glad_init_value = gladLoadGL();
    if( glad_init_value == 0 ) {
        std::cerr<<"Failed to Init GLAD"<<std::endl;
        abort();
    }


    std::cout<<"OpenGL information: VENDOR      : "<<glGetString(GL_VENDOR)<<std::endl;
    std::cout<<"                    RENDERDER   : "<<glGetString(GL_RENDERER)<<std::endl;
    std::cout<<"                    VERSION     : "<<glGetString(GL_VERSION)<<std::endl;
    std::cout<<"                    GLSL VERSION: "<<glGetString(GL_SHADING_LANGUAGE_VERSION)<<std::endl;



    // ************************************************* //
    //             1 - Setup Shaders                     //
    // ************************************************* //

    std::cout<<"*** Setup Shader ***"<<std::endl;

    // ******************************** //
    // 1.1 Define vertex and fragment shader
    // ******************************** //

    const char* vertex_shader_txt = "                                      \n \
            #version 330 core                                              \n \
            layout (location = 0) in vec4 position;                        \n \
            void main()                                                    \n \
            {                                                              \n \
                gl_Position = position;                                    \n \
            }";
    const char* fragment_shader_txt = "                                    \n \
            #version 330 core                                              \n \
            out vec4 FragColor;                                            \n \
            void main()                                                    \n \
            {                                                              \n \
                FragColor = vec4(1.0, 0.0, 0.0, 1.0);                      \n \
            }";



    // ******************************** //
    // 1.2 Create shader program
    // ******************************** //

    // (Warning: the following code doesn't perform error checking)

    //  A. Compile each shader separately
    // ******************************************* //

    const GLuint vertex_shader   = glCreateShader(GL_VERTEX_SHADER);
    const GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);

    glShaderSource(vertex_shader, 1, &vertex_shader_txt, nullptr);
    glCompileShader(vertex_shader);

    glShaderSource(fragment_shader, 1, &fragment_shader_txt, nullptr);
    glCompileShader(fragment_shader);

    //  B. Link shaders into shader program
    // ******************************************* //

    const GLuint shader = glCreateProgram();
    glAttachShader(shader, vertex_shader);
    glAttachShader(shader, fragment_shader);
    glLinkProgram(shader);

    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);


    // ************************************************* //
    //           2 - Sending data to GPU                 //
    // ************************************************* //

    std::cout<<"*** Setup Data ***"<<std::endl;

    // 2.1 Setup contiguous array of floating point value
    // ******************************************* //
    const std::vector<GLfloat> position = {
        -0.5f, -0.5f, 0.0f,
         0.5f, -0.5f, 0.0f,
         0.0f,  0.5f, 0.0f
    };

    // 2.2 Create VBO - Send data to GPU
    // ******************************************* //

    GLuint vbo = 0;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, position.size()*sizeof(GLfloat), &position[0], GL_STATIC_DRAW );
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // 2.3 Create VAO - Relation between VBO organization and input variables of shaders
    // ******************************************* //
    GLuint vao = 0;
    glGenVertexArrays(1,&vao);
    glBindVertexArray(vao);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glEnableVertexAttribArray( 0 );
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, nullptr );
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);






    // ******************************** //
    // Main loop
    // ******************************** //

    std::cout<<"*** Start GLFW loop ***"<<std::endl;
    while( !glfwWindowShouldClose(window) ) {

        // ************************************************* //
        //           3 - Displaying Data                     //
        // ************************************************* //

        glUseProgram(shader);             // Activate shader program
        glBindVertexArray(vao);           // Activate attributes for the drawing
        glDrawArrays(GL_TRIANGLES, 0, 3); // Draw 3 vertices
        glBindVertexArray(0);
        glUseProgram(0);


        glfwSwapBuffers(window);
        glfwPollEvents();
    }
    std::cout<<"*** Terminate GLFW loop ***"<<std::endl;


    glfwTerminate();

    return 0;
}