Hi there! I’m pretty new to OpenGL and I’m currently working on a small game engine to use as a code example to show employers. I’m working in C++ and have written a renderer implementation that provides a method to render a mesh. I’m looking for advice on how to improve the implementation and to point out any glaring mistakes I have made!
Here are the class .h and .cpp files:
Renderer.h
#pragma once
#include <iostream>
#include "GL\glew.h"
#include "GL\freeglut.h"
#include "glm\vec4.hpp"
#include "Structures\Mesh.h"
#include "Structures\Texture.h"
#include "Structures\Shader.h"
namespace Core
{
// A class that offers functionality to render types of objects given
// that objects definition and transform. In general it can be used
// to render 3D meshes using OpenGL shaders. This is an OpenGL specific
// implementation for this project.
class Renderer
{
public:
// Creates a new renderer with a specific background colour, this
// is the colour displayed behind rendered objects in the view.
Renderer(const glm::vec4& backgroundColour);
// Initialises the renderer by setting up the OpenGL environment.
virtual void Initialise() const;
// Sets the renders matrix mode, defaults to projection.
virtual void SetupMatrixMode() const;
// Clears the render to the background colour set when the renderer
// was constructed
virtual void Clear() const;
// Used to facilitate double buffering
virtual void SwapBuffers() const;
// Renders a given mesh with a texture and a shader. The projection
// and view transforms are supplied to specify the position and orientation
// of the render view and the model transform specifies the position,
// orientation and scale of the mesh.
virtual void RenderMesh(
const Structures::Mesh& mesh,
const Structures::Texture& texture,
const Structures::Shader& shader,
const glm::mat4& projectionTransform,
const glm::mat4& viewTransform,
const glm::mat4& modelTransform
);
private:
glm::vec4 backgroundColour;
// This variable is supplied to optimise the render code, if the same
// shader program is needed more than once repeatedly it is not
// reassigned to OpenGL unnecessarily.
GLuint lastUsedShaderProgram;
};
}
Renderer.cpp
#include "Renderer.h"
namespace Core
{
Renderer::Renderer(const glm::vec4& backgroundColour) :
backgroundColour(backgroundColour),
lastUsedShaderProgram(-1)
{
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); // DEPTH: use depth buffer, DOUBLE: double render to avoid flicker, RGBA: colour channel
}
void Renderer::Initialise() const
{
glewInit(); // Must be called after window has been initialized
IsGlewSupported();
glEnable(GL_DEPTH_TEST); // turn on depth testing using the graphics card
glPolygonMode(GL_FRONT, GL_FILL);
// Enable alpha blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glFrontFace(GL_CW); // Can be used to specify face vertex ordering
}
void Renderer::SetupMatrixMode() const
{
glMatrixMode(GL_PROJECTION);
}
void Renderer::Clear() const
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear colour and depth bits
glClearColor(backgroundColour.x, backgroundColour.y, backgroundColour.z, backgroundColour.w); // Clear to black
}
void Renderer::SwapBuffers() const
{
glutSwapBuffers();
}
void Renderer::RenderMesh(
const Structures::Mesh& mesh,
const Structures::Texture& texture,
const Structures::Shader& shader,
const glm::mat4& projectionTransform,
const glm::mat4& viewTransform,
const glm::mat4& modelTransform
)
{
// Bind vertices
glBindVertexArray(mesh.GetVertexArrayObject());
// Setup program
GLuint currentShaderProgram = shader.GetProgram();
if(currentShaderProgram != lastUsedShaderProgram)
{
glUseProgram(currentShaderProgram);
}
lastUsedShaderProgram = currentShaderProgram;
// Apply the texture to the shader texture sampler
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.GetTextureObject());
glUniform1i(shader.GetTextureSampler(), 0);
// Calculate transformation
glm::mat4 mvpTransform = projectionTransform * viewTransform * modelTransform;
// Apply transformation
GLuint shaderMvpTransform = shader.GetMvpTransform();
glUniformMatrix4fv(shaderMvpTransform, 1, GL_FALSE, &mvpTransform[0][0]);
// Draw
glDrawArrays(GL_TRIANGLE_STRIP, 0, mesh.GetVertices().size()); // GL_LINE_LOOP for wire mesh, GL_TRIANGLES for filled mesh
}
}
Apologies if this is too much of a code dump! I’ve not included the mesh, texture and shader classes with this as things would start to get a little out of hand.