Unity support many kinds of rendering paths. For now there are three
types of rendering path in Unity: forward
, deferred
, and vertex lit (almost never use)
rendering path.
An example of setting rendering path
in Unity Shader
Pass { Tags{ "LightMode" = "ForwardBase" } }
The Below Table shows the
Common
Rendering Path Option for LightMode Tag in Unity Shader
Tag Name | Description | |
---|---|---|
Always | This Pass will be rendered in any rendering path, but it will not calculate any lighting | |
ForwardBase | Used for forward rendering. The Pass will calculate the environmetal light, directional light, per-vertex /Spherical Harmonics(SH) light source, and Lightmaps | |
ForwardAdd | Used for forward rendering. The Pass will calculate additional per-pixel light source, every Pass corresponding one light source | |
Deferred | Used for deferred rendering. This Pass will render G-Buffer(includes color, normal, Buffer in world space) | |
ShadowCaster | Render the object’s depth info into the shaowmap or a depth map |
For each forward rendering, we need to render
the rendering primitive of the object and calculate
the data of two buffers (color
buffer and depth
buffer). We use the depth buffer
to determine
if a fragment is visible
and update
the color value of the color buffer if it is visible
.
Pseudo code:
Pass
{
for(each primitive in this model)
{
for(each fragment covered by this primitive)
{
if(failed in depth test)
{
discard;
}
else
{
float4 color = Shading(materialInfo, pos, normal, lightDir, viewDir);
WriteFrameBuffer(fragment, color);
}
}
}
}
Deferred Rendering
mainly includes two Pass
. The first
Pass, we don’t
do any lighting calculations, and only
calculate which fragment in the screen is visible
through depth buffer
. After
finding a fragment is visible, it will store
the data into the G-Buffer
. Then, in the second
Pass, it will use
the data of fragment in the G-Buffer to do the lighting calculation.
Pseudo code:
PassOne // Store fragment data into G-Buffer
{
for(each primitive in this model)
{
for(each fragment covered by this primitive)
{
if(failed in depth test)
{
discard;
}
else
{
WriteGBuffer(materialInfo, pos, normal, lightDir, viewDir);
}
}
}
}
PassTwo // Calcaulate Lighting by using the data in G-Buffer
{
for(each pixel in the screen)
{
if(the pixel is valid)
{
readGBuffer(pixel, materialInfo, pos, normal, lightDir, viewDir);
float4 color = Shading(materialInfo, pos, normal, lightDir, viewDir);
WriteFrameBuffer(pixel, color);
}
}
}
Normally we will use
Forward Rendering
, but when the scene hastoo many light sources
, theperformance
of Forward Renderingdrops
dramatically.
For example, if we place multiple light sources in an area in the Unity Scene, and these light source areas overlap and influence with each other. In order to get the final lighting effects, we need to perform multiple Pass for each object in the area to calculate the lighting result of different light source to this object, finally, blend these results in the color buffer to get the final lighting. Therefore, every time when we call a Pass we need to render the object again, but many calculations actually is repeat.
Deferred Rendering can solve this problem because it
not only
usescolor buffer
, anddepth buffer
, it also use an additional buffer calledG-Buffer
(Geometry- Buffer). G-Bufferstores
the information of the surface we care (normally it means the surface which is the closest to camera), such as the surface’s Normal, Position, Material Properties used for illumination calculation, etc.
End –Cheng Gu