Mesh Drawing
The library handles mesh along two main type of classes:-
- A class
meshthat stores the vertex data (position, normal, uv, etc.) on the CPU. This class can be used to initialize a mesh and modify their individual vertex value, but cannot be displayed directly. -
- A class
mesh_drawablethat stores the OpenGL buffers (VBOs, VAO, textures, etc.), and some uniform variables (global shape color, model matrix, etc.). This class is used to display efficiently the corresponding mesh, but the vertex value cannot be directly accessed via the code.
Display a mesh
The process to display a primitive in a standard scene structure is the following.-
1) Create a shared variable of type mesh_drawable in the class scene (e.g. in
scene.hpp)
struct scene_structure { // ... cgp::mesh_drawable cube_drawable; // ... }
- 2) Initialize the mesh_drawable variable in the initialize function
void scene_structure::initialize() { // ... // Create a temporary mesh structure mesh cube = mesh_primitive_cube(); // - Create the primitive as mesh // Initialize the mesh_drawable from the mesh cube_drawable.initialize_data_on_gpu(cube); // This initialize the OpenGL buffers on cube_drawable from the data stored in the variable cube }
- Notes
- - The mesh structure stores the data in buffers (numarray) accessible in the main memory RAM. It is a convenient to manipulate the buffers in the code, but the data cannot be displayed as it is.
- - The mesh_drawable stores the identifiers of the buffers objects sent to the GPU memory (+ some additional uniform data). At the oppositve of the mesh structure, the buffer data cannot be manipulated via mesh_drawable, but it can be displayed.
- - The mesh_drawable.initialize_data_on_gpu(mesh) send all the buffers stored in the mesh structure in RAM to the GPU memory, and keep the VBO identifiers. The initialize function consists of a series of glBufferData calls.
-
3) Call the drawing of the mesh_drawable variable in the
display_framefunction
void scene_structure::display_frame() { // ... draw(shape, environment); // Note: environment is a variable that contains the scene parameters // ex. camera, light, etc. }
void scene_structure::display() { // ... // change the color parameter shape.material.color = { 1.0f, 1.0f, 0.8f}; // change the translation parameter shape.model.translation = { 1.5f,0,0 }; // the current color is used when calling draw(...) draw(shape, environment); // a wireframe call is also available by default draw_wireframe(shape, environment); }
Draw call
The display a drawable entity follows the main general steps: Set current shader, send uniform parameters, display calls. Two variables are needed for thedraw(...) function
-
- The drawable element to be displayed (ex. a
mesh_drawable) storing the VBO identifier of the data, as well as some parameters used as uniforms for the shader. This element also stores the id of the shader to be used. - - An environment that describes elements that are needed for the shader, but are not depending directly of the element itself (typically shared through all the objects of the scene).
The draw call of a mesh_drawable element can be summarized as follows
draw(drawable, environment)
1) Set current shader attached to drawable element
2.a) Send uniforms parameters attached to the drawable element
2.b) Send uniforms parameters attached to the environment
3) Set texture of the drawable element
4) Draw calls on the drawable vbo (data already stored on the GPU)
5) Cleaning buffers state
glUseProgram( drawable.shader )
2.a) Send uniforms parameters attached to the drawable element
glUniform( drawable.[parameters] ) ... on transform and shading values
2.b) Send uniforms parameters attached to the environment
glUniform( environment.[parameters] ) ...
3) Set texture of the drawable element
glBindTexture(GL_TEXTURE_2D, drawable.texture)
4) Draw calls on the drawable vbo (data already stored on the GPU)
glBindVertexArray( drawable.vao )
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, drawable.connectivity)
glDrawElements(GL_TRIANGLES)
5) Cleaning buffers state
glBindVertexArray(0)
glBindTexture(GL_TEXTURE_2D, 0)
Environment variable
The environment structure describes the variables and states that are necessary to draw an element and is used by the shader, but does conceptually depends on the global scene rather than an individual element.Pre-existing scene provide a typical default basic environment
struct environment_structure : environment_generic_structure { // Color of the background of the scene vec3 background_color = {1,1,1}; // Used in the main program // The position/orientation of a camera that can rotates freely around a specific position mat4 camera_view; // A projection structure (perspective or orthogonal projection) mat4 camera_projection; // The position of a light vec3 light = {1,1,1}; };
During the draw call, the environment parameters are sent to the shader via the function
void opengl_uniform(GLuint shader, scene_environment const& scene)
uniform_generic_structure can also be used to add new uniform parameters to an existing environment structure without re-definition.
13_opengl/uniform/uniform.hpp
struct environment_structure { // ... // generic container for uniform values (pairs of string/value) uniform_generic_structure uniform_generic; };
GUI
The interface is using ImGui library.- - The state of the variables can be stored in the gui_parameters structure, and therefore shared in the scene class.
- - The gui elements are created in the display_gui function using direct ImGui calls.
- - The use of the gui elements that impacts the display of drawable elements can be typically handled in the display() function.
An example of simple use of the gui is the following
// In scene.hpp struct gui_parameters { bool display_frame = true; bool display_wireframe = false; };
// In scene.cpp void scene_structure::display_gui() { ImGui::Checkbox("Frame", &gui.display_frame); ImGui::Checkbox("Wireframe", &gui.display_wireframe); ImGui::SliderFloat("Translation", &shape.model.translation.x, -2.0f, 2.0f); }
// In scene.cpp void scene_structure::display_frame() { // ... draw(shape, environment); if(gui.display_wireframe) draw_wireframe(shape, environment); }