Rendering pipelines used by modern rendering frameworks consist of following stages:
- Data Loading
- Shading & Lighting
- Optional rendering stages
In sections below, I describe each stage in detail to showcase what modern rendering frameworks share with my rendering framework. Picture below summarizes entire rendering pipeline:
Modern rendering pipeline diagram |
Red block "DATA" represents input to the pipeline while the blue block "SCREEN" represents final step (output) where contents of Frame Buffer are displayed onto a screen.
3.1 Data Loading
Modern GPUs use batching which merges objects with same materials together to save memory and draw calls. When Command Buffer contains "Render State" command GPU starts its drawing procedure which is expensive, thus batching needs to be initiated.
3.2 Shading & Lighting
After data are loaded into VRAM a special type of program is executed on GPU for each vertex and pixel that belongs to the currently rendered object. This program is called "shader" and is specifically designed for GPUs only.
There are several types of shaders:
- Vertex shader
- Fragment shader
- Surface shader
- Compute shader
3.2.1 Vertex Shader
Vertex shader function can be used to distort object’s geometry, calculate vertex lighting or important fog data. Most important functionality of vertex shader is to transform vertices from object (local) space into clip space using MVP matrix. Such operation is defined by the following relation:
Where vector "P" represents final vertex clip space position, vector "V" defines vertex position in object (local) space while the "MVP" represents Model-View-Projection matrix.
After rasterization process is completed, a fragment (pixel) shader function is called for each pixel that belongs to currently rendered object. In this procedure each pixel can be modified manually to produce per-pixel effects.
In Unity Engine, using surface shader is often more time efficient and easier to implement since user doesn’t have to create both vertex & fragment functions with their own specific definitions. Surface shaders create vertex / fragment functions from one "surf" function which implements PBR by default.
Compute shaders can be utilized when the full power of GPU’s parallel processing is needed to accomplish arbitrary tasks such as particle simulation, AI pathfinding or any other CPU heavy computations.
Optional stages of rendering pipeline usually include following processes:
Where vector "P" represents final vertex clip space position, vector "V" defines vertex position in object (local) space while the "MVP" represents Model-View-Projection matrix.
Vertices are defined in their object (local) space from where they are transformed into world space using Model matrix. Then another transformation takes place which transforms vertex from world space into view space (relative to camera / eye) using View matrix. Last transformation uses Projection matrix to transform vertex from view space into clip space where each clip coordinate X, Y and Z is divided by clip coordinate W (also called perspective division) to produce NDC (Normalized Device Coordinates) which range is from -1 to 1. As a final step NDCs are scaled and translated by the viewport parameters to produce Window coordinates.
3.2.2 Fragment Shader
After rasterization process is completed, a fragment (pixel) shader function is called for each pixel that belongs to currently rendered object. In this procedure each pixel can be modified manually to produce per-pixel effects.
3.2.3 Surface Shader
In Unity Engine, using surface shader is often more time efficient and easier to implement since user doesn’t have to create both vertex & fragment functions with their own specific definitions. Surface shaders create vertex / fragment functions from one "surf" function which implements PBR by default.
3.2.4 Compute Shader
Compute shaders can be utilized when the full power of GPU’s parallel processing is needed to accomplish arbitrary tasks such as particle simulation, AI pathfinding or any other CPU heavy computations.
3.3 Optional rendering stages
- Culling – decides which faces should and shouldn’t be drawn
- Blending – properly blends pixels of transparent meshes
- Stencil test – test against bit mask to decide which pixels should be drawn and which should be discarded
- Color Masking – Test against color mask to decide which color channels should be ignored
3.4 Frame & Depth Buffer
Both frame & depth buffers are managed by the GPU and their functionality differs in a sense that frame buffer stores final RGB image outputted by the rendering pipeline while a depth buffer (also known as Z-Buffer) stores depth for each pixel.
Depth data are important to properly execute depth testing for all objects as well as for other image effects like fog or depth-of-field.
Depth data are important to properly execute depth testing for all objects as well as for other image effects like fog or depth-of-field.
3.5 Double Buffering
When application has finished its graphical calculations and frame buffer is updated, drawing process then accesses frame buffer and redraws the screen. This might be problematic for single buffered applications where an application tries to rewrite frame buffer while graphical process is still reading from it which leads to unwanted screen tearing.
Solution comes in form of double buffering where two buffers are used instead of one. Then synchronization takes place which assures that one of the buffers will be read only while the other one will be overwritten. This solves the screen tearing problem since there is no longer a conflict between application processing speed and rendering processing speed.
Solution comes in form of double buffering where two buffers are used instead of one. Then synchronization takes place which assures that one of the buffers will be read only while the other one will be overwritten. This solves the screen tearing problem since there is no longer a conflict between application processing speed and rendering processing speed.
No comments:
Post a Comment