GridPro Graphics API Revamp documentation.
- About
- Existing RenderPipeline
- Challenges in Porting
- Solutions
- Renderer API Usage
- Renderer API Reference
To replace Fixed pipeline approach with shader approach in GridPro WS.
Existing RenderPipeline Structure & Configuration exists as
-
MVP pattern is used to seperate MODEL <-> PRESENTER_LAYER <-> VIEW using
Gp_gui_Models <-> Gp_gui_presenter <-> Gp_gui_view
classes -
A class derived from
QApplication
class called ->Gp_gui_Application
which hasGp_gui_mainwindow
-
Gp_gui_mainwindow
has subwindow attached calledgp_gui_glwidget
-
gp_gui_glwidget
class is derived fromQOGLWiget
, is used to setup windowing, OpenGL context, Scene Configuration (Not Exactly but setting up mvp from camera pos , view volume evaluation , peripheral input handling etc...) -
gp_gui_glwidget::paintGL()
is where frame rendering starts. -
Inside
gp_gui_glwidget::paintGL
, a reference for gp_gui_model objects are accquired.
Since bare data structures like topology do not contain all the data to represent all visual aspects of topology model, a new model data structure is built by inheriting base topology data structure & additionally data members & methods are created for rendering all aspects, properties of topology model.
- Get avaliable gp_gui_model from
Gp_gui_mainwindow::view() -> presenter();
For topology
Gp_gui_topology & topology = Gp_gui_mainwindow::view() -> presenter() -> topology_model();
For grids
Gp_gui_multiblock_grid_list & gp_grids = Gp_gui_mainwindow::view() -> presenter() -> grid_model()
Gp_gui_multiblock_grid * curr_grid = gp_grids.get_current_grid();
For cad model
Gp_gui_minicad & cad_model = Gp_gui_mainwindow::view() -> presenter() -> cad_model()
topology.draw_surface_displaylist()`
- Models contain view methods like
model.render()
- Example :
topology.draw_surface_render()
which binds the model data structure to a render api paradigm. - Mild & Extreme Explicit API's like
OpenGL 3.3, OpenGL 4.3
&Vulkan , DirectX
cannot be used in this manner.
- Create a wrapper Model class to encapsulate all
OpenGL 2.1
,OpenGL 3.3
calls into a custom Renderer API & replace them. (Not an Elegant solution as i thought initially but works)
-
Create a Model Object ("Renderable Model in OpenGL context" not to be confused with actual data structure)
class Renderer_API::Model LinearSurfaceSegment;
-
Set Layout of the vertex Array (*very important)
LinearSurfaceSegment.setVertexAttribLayout(Renderer_API::VertexArray::Layout::VN);
-
Pass the Data
std::vector<float> pos, normal; // set some data LinearSurfaceSegment.setVertexAttribData(&pos, nullptr, &normal);
-
Set Shading type, Lighting, material etc
LinearSurfaceSegment.setShadeModel(Renderer_API::ShadeModel::FLAT); LinearSurfaceSegment.setLighting(false);
-
Set Primitive Type
LinearSurfaceSegment.setPrimitiveType(Renderer_API::Model::PrimitiveType::TRIANGLE);
-
Render in the Scene
Scene.render(LinearSurfaceSegment);
- Create a Proper
(RenderableEntity -> SceneRenderer)
abstraction system. - Seperate the
Model_Data
<->
Renderer
properly. - No Graphics API calls inside Model class should allowed
- Use a Scene Class to manage
Camera System.
Calculation of view-projection matrices.
Setiing Lighting Parameter & Properties.
Setting model Visibility flags.
- This example is one avaliable interface for OpenGL_2_1_API. A new Interface will be Based on Interface Usage For using this interface include this header in your src file
#ifdef GP_USE_RENDERER_API
#include "../Model_Renderer_API/Model_Renderer_API_Core/renderer_api.hpp"
#endif
- Example Porting to new interface
void Gp_gui_topology::draw_corners_render() const
{
if(! get_num_corners_in_corner_group(current_corner_group) && ! get_num_corners_in_corner_group(ref_corner_group))
return;
#ifdef GP_USE_RENDERER_API
{
using namespace OpenGL_2_1_API;
Renderer::Model Corner_group(1);
Corner_group.setPrimitiveType(Renderer::PrimitiveType::POINTS);
if(! topology_corners_ref_group_indices_array.empty())
{
Corner_group.setMonoColor(ref_corner_color);
Corner_group.setVertexArray(topology_corner_positions_array);
Corner_group.setIndexArray(topology_corners_ref_group_indices_array);
Corner_group.render();
}
if(! topology_corners_cur_group_indices_array.empty())
{
Corner_group.setMonoColor(corner_color);
Corner_group.setVertexArray(topology_corner_positions_array);
Corner_group.setIndexArray(topology_corners_cur_group_indices_array);
Corner_group.render();
}
}
#endif
- OpenGL 2.1 Equivalent code
#ifndef GP_USE_RENDERER_API
GL_ERROR_CHECK;
bool lighting_is_enabled = glIsEnabled(GL_LIGHTING);
if(lighting_is_enabled)
glDisable(GL_LIGHTING);
glColor3ubv(&ref_corner_color.r);
if(! topology_corners_ref_group_indices_array.empty())
{
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 3*sizeof(GLfloat), &(topology_corner_positions_array[0]));
glDrawElements(GL_POINTS, topology_corners_ref_group_indices_array.size(),
GL_UNSIGNED_INT, &(topology_corners_ref_group_indices_array[0]));
glDisableClientState(GL_VERTEX_ARRAY);
GL_ERROR_CHECK;
}
if(is_in_motion)
glDepthFunc(GL_ALWAYS);
glColor3ubv(&corner_color.r);
if(! topology_corners_cur_group_indices_array.empty())
{
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 3*sizeof(GLfloat), &(topology_corner_positions_array[0]));
glDrawElements(GL_POINTS, topology_corners_cur_group_indices_array.size(),
GL_UNSIGNED_INT, &(topology_corners_cur_group_indices_array[0]));
glDisableClientState(GL_VERTEX_ARRAY);
GL_ERROR_CHECK;
}
if(lighting_is_enabled)
glEnable(GL_LIGHTING);
#endif
if(is_in_motion)
glDepthFunc(GL_LEQUAL);
}
- OpenGL 3.3 Equivalent
#ifdef GP_USE_RENDERER_OPENGL_3_3 // Pure OpenGL 3.3
OpenGL_3_3_API::Renderer::Shader::OpenGLShader ModelShader("Corner Shader" , OpenGL_3_3_API::Renderer::ShaderSources::simpleVertexShaderSource,
OpenGL_3_3_API::Renderer::ShaderSources::simpleFragmentShaderSource);
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
std::unordered_map<std::string, GLuint> VertexBufferObjects;
std::unordered_map<std::string, GLuint> IndexBufferObjects;
std::unordered_map<std::string, GLuint> VertexAttributeLocations;
std::unordered_map<std::string, GLuint> uniformLocations;
//----------------Pass Position Data ------------------------------------------------+
glUseProgram(ModelShader.ShaderProgram);
glGenBuffers(1,&VertexBufferObjects["position"]);
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferObjects["position"]);
glBufferData(GL_ARRAY_BUFFER, topology_corner_positions_array.size(), &topology_corner_positions_array[0] , GL_STATIC_DRAW);
// Get the Vertex Attribute location in GLSL shader code
VertexAttributeLocations["position"] = glGetAttribLocation(ModelShader.ShaderProgram, "position");
if(VertexAttributeLocations["position"] != -1)
{
printf("Found Vertex Attribute : position");
glEnableVertexAttribArray(VertexAttributeLocations["position"]);
glVertexAttribPointer(VertexAttributeLocations["position"], 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat) , 0);
}
else std::cerr << "No VertexAttributeLocation in shader with Name " << "position" << "\n";
glBindBuffer(GL_ARRAY_BUFFER, 0);
//----------------Pass index Data ------------------------------------------------+
// Create and a Index Buffer Object (VBO) for vertex attribute name "IndexBufferName"
std::string IndexBufferName = "index_data";
glGenBuffers(1, &IndexBufferObjects[IndexBufferName]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferObjects[IndexBufferName]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->topology_corners_ref_group_indices_array.size(), &this->topology_corners_ref_group_indices_array[0], GL_STATIC_DRAW);
//glBufferSubData(GL_ELEMENT_ARRAY_BUFFER , offset , &empty_array[0] );
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// ------------Pass Uniform Data -------------------------------------------------+
std::cout << " Projection matrix = " <<this->glm_projection_matrix[0][0] << "\n";
uniformLocations["projectionMatrix"] = glGetUniformLocation(ModelShader.ShaderProgram, "projectionMatrix");
uniformLocations["viewMatrix"] = glGetUniformLocation(ModelShader.ShaderProgram, "viewMatrix");
uniformLocations["modelMatrix"] = glGetUniformLocation(ModelShader.ShaderProgram, "modelMatrix");
glUniformMatrix4fv(uniformLocations["projectionMatrix"], 1, GL_FALSE, glm::value_ptr(this->glm_projection_matrix));
glUniformMatrix4fv(uniformLocations["viewMatrix"], 1, GL_FALSE, glm::value_ptr(this->glm_view_matrix));
glUniformMatrix4fv(uniformLocations["modelMatrix"], 1, GL_FALSE, glm::value_ptr(this->glm_model_matrix));
uniformLocations["changing_color"] = glGetUniformLocation(ModelShader.ShaderProgram, "changing_color");
glUniform3f(uniformLocations["changing_color"], 1.0f, 1.0f, 1.0f);
glPointSize(10.0f);
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferObjects["position"]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferObjects[IndexBufferName]);
glEnable(GL_DEPTH_TEST);
//glDrawArrays(GL_POINTS , 0, topology_corner_positions_array.size());
//glDepthFunc(GL_ALWAYS);
glDrawElements(GL_POINTS, topology_corners_cur_group_indices_array.size(), GL_UNSIGNED_INT, nullptr); // &(topology_corners_cur_group_indices_array[0])
GLuint PrimitiveID = OpenGL_3_3_API::Renderer::utils::retrieve_selected_primitive_ID(this->mouse_x ,this->mouse_y ) - 1;
std::string selected_id = "Selected Corner = " + std::to_string(PrimitiveID);
messg_statusbar(selected_id.c_str());
glDeleteBuffers(1, &VertexBufferObjects["position"]);
glDeleteBuffers(1, &IndexBufferObjects[IndexBufferName]);
glDeleteVertexArrays(1, &VAO);
glUseProgram(0);
- Create a gp_gui_class by inheriting the topology (already implemented) & instead of maintaining a lot of variables , containers to store vertices, indices, color_data ,
surface_ids , etc - Use RenderableEntity class to group together all required data.
class gp_gui_topology : public topology
{
public :
std::unordered_map<std::string, std::map<uint32_t, Renderer_API::RenderableEntity>> topo_surfaces,
std::unordered_map<std::string, Renderer_API::RenderableEntity> topo_corners, topo_edges;
// Member functions to create renderable entities and set flags
};
Example for setting corners:
topo_corners["assigned_corners"].setPrimitiveType(Renderer_API::PrimitiveType::POINTS);
topo_corners["assigned_corners"].setVertexArray(vertexarray);
topo_corners["assigned_corners"].setColorSchema(Renderer_API::ColorSchema::PER_VERTEX);
topo_corners["assigned_corners"].setColorArray(colorarray);
//Optional
float shininess;
glm::vec3 ambient, diffuse, specular;
topo_corners["assigned_corners"].setMaterialPty(ambient, diffuse, specular, shininess);
Example for setting other 3d linear surface segments:
topo_surfaces["linear_surface_segments"][1].setPrimitiveType(Renderer_API::PrimitiveType::POINTS);
topo_surfaces["linear_surface_segments"][1].setVertexArray(vertexarray);
topo_surfaces["linear_surface_segments"][1].setColorSchema(Renderer_API::ColorSchema::PER_PRIMITIVE);
float shininess;
glm::vec3 ambient, diffuse, specular;
topo_surfaces["linear_surface_segments"][1].setMaterialPty(ambient, diffuse, specular, shininess);
topo_surfaces["linear_surface_segments"][1].setColorArray(colorarray);
In paintGL use Scene Class object to render
Gp_gui_topology & topology = Gp_gui_mainwindow::view() -> presenter() -> topology_model();
if(topology.isUpdated())
topology.updateRenderableEntities(); // ReEvaluate the RenderableEntities based on flags other wise cached data is rendered
std::vector<Renderer_API::RenderableEntity>& Topo_RenderableEntitiesList = topology.getRenderableEntities();
Scene.Render(Topo_RenderableEntitiesList, topology_display_flags);
// Similarly for Grids, Cad Model, Control Net
If you encounter any issues or have questions, please don't hesitate to open an issue on GitHub.
Happy coding!