Like the engine I made two years ago, I implemented the Composite Reuse Principle over inheritance, which allows me to create objects with different behaviors adding one or other component to instances of the same base class. I have called this base class as GameObject which contains the name of the object, a color to tint the whole object, a container of children objects, a container of components and a pointer to its parent. This few attributes allow me to identify the object, have a hierarchy and make the object do what I want it to do. Also the GameObject class have the method update that will call the update of every component.
- Transform: has the data needed by the object to define the position, rotation and scale of the object in the space that is contained.
- Camera: with this component the object can be used to render the scene from its point of view, it has the field of view, aspect ratio, near and far plane of the Camera, and the view and projection matrices. Also has methods to orientate the transform to some point in the space (lookAt) and update the perspective.
- Light: this component gives to the object the capability to light the scene. Stores all the data needed to define the 3 types of lights that use to be in a game: Directional Light, Point Light and Spot (or Focus) Light. Also it has the Ambient, Specular and Diffuse light components, since my Shading Model implements for each Light. And I thought could be useful a method to orientate the transform to some point in the space (lookAt).
- ObjectRenderer: this component stores the Mesh and the Texture data that will represent the object on the screen.
This class contains the group of objects that are in the world that we are rendering, we can have different instances to create different scenes to render. Apart from the GameObject pointer container I have a container for the Cameras and the Lights components of the scene, to have a fast access to them on the Renderer. Also it has an update method to update all the GameObjects.
The Renderer manage the Render Pipeline, it receive the GameObjects, Lights and the active Camera of the Scene, and the type of render to use, Forward or Deferred. For each type of render has a method that implements each technique:
- Forward: iterates over every GameObject that has received, and for each object iterates over every Light received. Updates the data of the object, the light and the Camera to the shader, and renders to the canvas after calculating the matrices and vectors needed to do it.
- Deferred: when the rendered is created initialize the GBuffer with the Albedo, Normals and Depth of the scene, so when this method is called, generates the GBuffer with the data taken from all the GameObjects received and the Camera (Geometry Pass), and once the GBuffer is generated, renders the frame calculating the illumination using the GBuffer and every Light data (Lightning Pass).
Forward Rendering vs Deferred Rendering
Once created the Engine, and some Scenes to do some tests I could see the differences between them and confirm what I have learnt during the study of the techniques.
Looking at the implementation of each technique we can say that the complexity of the Forward Rendering is , and for the Deferred Rendering is [lates]O(N_geometry_fragments + L_lights)[/latex]. Knowing that we could say that if the Scene has lots of objects but only one light, and vice-versa, both implementations will have the same performance. But at the moment we have more than one of both elements, the Deferred performance will be better than the Forward.
But in the other hand, the basic Deferred Shading has some limitations when it has to work with more than one material or transparencies, to implement this features we should use diferent techniques of the Deferred Rendering, meanwhile the Forward is able to do it.
The next canvas is an interactive implementation of my Engine