Location>code7788 >text

Three rendering paths in Unity

Popularity:607 ℃/2024-09-19 11:30:07

Render paths in Unity

Unity's Render Path

In Unity, the Rendering Path determines how lighting is applied to a Unity Shader. Therefore, the lighting calculations for a shader can only be performed correctly if we have correctly selected and set the required Rendering Path for the shader.

Render paths in unity:

  • Forward Rendering Path
  • Deferred Rendering Path.
  • Vertex Lit Rendering Path [Deprecated after Unity].

In most cases, a project will only use one render path.

Forward Rendering Path

The forward rendering path is the traditional rendering method and the one we use most often.

Forward rendering path principle:

In order to perform a complete forward rendering process, we need to render the rendered tuples of the object and compute the information in two buffers: the color buffer and the depth buffer. The depth buffer is used to determine if a piece element is visible, and if it is, to update the color value in the color buffer.

Pass {
for (each primitive in this model) {
for (each fragment covered by this primitive) {
if (failed in depth test) {
// if failed in depth test, the fragment is invisible
discard; } else {
              } else {
// If the fragment is visible
// then do the lighting calculation
float4 color = Shading(materialInfo, pos, normal, lightDir, viewDir); // Update the frame buffer.
// Update the frame buffer
writeFrameBuffer(fragment, color); }
}
}
}
}

For each pixel-by-pixel light source, we need to perform the complete rendering process above once.

If an object is within the area of influence of multiple pixel-by-pixel light sources, then the object will need to perform multiple Passes, each of which computes the lighting results of one pixel-by-pixel light source, and then blends those lighting results in the frame buffer to get the final color value.

Forward rendering in Unity:

3 ways to handle lighting for forward rendering paths in Unity:

Vertex-by-vertex, pixel-by-pixel, and Spherical Harmonics (SH) processing.

And deciding which processing mode to use for a light source depends on its type and rendering mode.

Light type: whether the light source is parallel light or other types of light sources

Rendering mode of the light source: whether it is Important or not

In forward rendering, when we render an object, Unity renders it based on the scene'sSetting of each light sourceas well as theseDegree of influence of the light source on the object(e.g., proximity to the object, intensity of the light source, etc.) An importance ranking of these light sources is performed. Where a certain number of light sources are processed on a pixel-by-pixel basis and thenUp to 4 light sources are treated on a vertex-by-vertex basis, and the remaining light sources can be treated as SH.

  • The brightest parallel light in the scene is always treated on a pixel-by-pixel basis.
  • Light sources whose rendering mode is set to Not Important are treated on a vertex-by-vertex or SH basis.
  • Light sources whose rendering mode is set to Important are processed on a pixel-by-pixel basis.
  • If the number of pixel-by-pixel light sources obtained according to the above rule is less than the number of pixel-by-pixel light sources (Pixel Light Count) in the Quality Setting, more light sources will be rendered on a pixel-by-pixel basis.

img

Two kinds of Pass in forward rendering , light calculation in Pass.

For forward rendering, theA Unity Shader usually defines a Base Pass (Base Passes can also be defined multiple times, e.g. for cases where two-sided rendering is required, etc.) and an Additional Pass.

A Base Pass will only be executed once (except when multiple Base Passes are defined), while an Additional Pass will be called multiple times depending on the number of other pixel-by-pixel light sources affecting the object, i.e., one Additional Pass will be executed for each pixel-by-pixel light source.

Vertex Lit Rendering Path

The Vertex Lighting Render Path is the least demanding and the most computationally efficient, but it is also the least effective, as it does not support pixel-by-pixel effects, such as shadows, normal mapping, and high-precision highlight reflections. In fact, it is only a subset of the forward rendering path, which means that all the features that can be realized in the vertex lighting rendering path can be done in the forward rendering path.

If you choose to use the vertex lighting render path, then Unity will populate only those light source variables that are vertex-by-vertex related, meaning that we can't use some pixel-by-pixel lighting variables.

Vertex lighting rendering in Unity:

The vertex lighting rendering path is usually done for an object in a single Pass. In this Pass, we calculate the illumination of the object from all the light sources we care about, and this calculation is handled on a vertex-by-vertex basis. This is the fastest render path in Unity and has the widest hardware support (but it is not supported on consoles).

Accessible built-in variables and functions:

In Unity, we can access up to 8 vertex-by-vertex light sources in a vertex-illuminated Pass.

img

Built-in variables that can be used in vertex lighting rendering paths

img

Built-in functions that can be used in vertex lighting rendering paths

Deferred Rendering Path

Deferred rendering is a much older rendering method, but has come back into vogue in recent years due to the bottlenecks that forward rendering can cause as described above.

In addition to the color buffer and depth buffer used in forward rendering, deferred rendering makes use of additional buffers, which are also collectively referred to as theG-buffer, where G is an abbreviation for Geometry.The G-buffer stores additional information about the surface we are interested in (usually referred to as the surface closest to the camera), such as the normals of that surface, its position, the material properties used for lighting calculations, and so on.

Principles of delayed rendering:

Delayed rendering consists of two main Passes.

In the first Pass, we do not perform any illumination computation, but only compute which slices are visible, which is mainly achieved by the deep buffer technique, when a slice is found to be visible, we store its relevant information into the G-buffer.

Then, in the second Pass, we utilize the information of individual slices of the G-buffer, such as surface normals, viewing directions, diffuse reflection coefficients, etc., to perform the real illumination calculation.

        Pass 1 {
            // The first pass does not perform any real lighting calculations.
            // only stores the information needed for the illumination calculation in the G-buffer.

            for (each primitive in this model) {

              for (each fragment covered by this primitive) {
                  if (failed in depth test) {
                    // if failed in depth test, the fragment is invisible
                    discard; } else {
                  } else {
                    // If the fragment is visible
                    // then store the required information in the G-buffer
                    writeGBuffer(materialInfo, pos, normal, lightDir, viewDir); }
                  }
              }
          }
        }

        Pass 2 {
          // Use the information in the G-buffer to perform real lighting calculations.

          for (each pixel in the screen) { if (the pixel is valid) {
              if (the pixel is valid) {
                  // if the pixel is valid
                  // read the G-buffer corresponding to the pixel.
                  readGBuffer(pixel, materialInfo, pos, normal, lightDir, viewDir);

                  // Calculate the lighting based on the read information.
                  float4 color = Shading(materialInfo, pos, normal, lightDir, viewDir); // Update the frame buffer.
                  // Update the frame buffer
                  writeFrameBuffer(pixel, color); // Update the frame buffer.
              }
          }
        }

The number of Passes used for deferred rendering is usually two, which is independent of the number of light sources included in the scene.

in other wordsThe efficiency of deferred rendering does not depend on the complexity of the scene, but is related to the size of the screen space we use.

This is because the information we need is stored in buffers that can be interpreted as a 2D image, and our computations are actually performed in these image spaces.

Deferred rendering in Unity:

Unity has two types of deferred rendering paths, a legacy deferred rendering path, the one used before Unity 5, and a mid-use deferred rendering path.If the game uses a lot of real-time lighting, then we may want to choose the deferred rendering path, but this path requires some hardware support.

For deferred rendering paths, it is best suited for situations where there are a large number of light sources in the scene and using forward rendering would cause a performance bottleneck. Also, each light source in a deferred rendering path can be processed on a pixel-by-pixel basis.

The disadvantage of delayed rendering:

  • True anti-aliasing is not supported.
  • Cannot handle translucent objects.
  • There are some requirements for the graphics card. To use deferred rendering, the card must support MRT (Multiple Render Targets), Shader Mode 3.0 and above, deep rendering textures, and double-sided stencil buffering.

Unity requires us to provide two Passes.

(1) The first Pass is used to render the G buffer.In this Pass, we render the object's diffuse color, highlight reflective color, smoothness, normal, self-illumination, and depth into a G-buffer in screen space. For each object, this Pass will be executed only once.

2) The second Pass is used to compute the true light model.This Pass will use the data rendered in the previous Pass to calculate the final light color, which is then stored in the frame buffer.

The default G-buffer (note that the contents of the render texture storage will vary from Unity version to Unity version) contains the following Render Texture (RT).

  • RT0: Format is ARGB32, RGB channels are used to store diffuse colors, A channels are not used.
  • RT1: The format is ARGB32, the RGB channel is used to store the highlight reflection color and the A channel is used to store the index portion of the highlight reflection.
  • RT2: Format is ARGB2101010, RGB channels are used to store normals, A channels are not used.
  • RT3: The format is ARGB32 (non-HDR) or ARGBHalf (HDR) for storing self-illumination + lightmap + reflection probes.

Depth buffer and template buffer.

When calculating lighting in the second pass, by default only Unity's built-in Standard lighting model can be used, if we want to use another lighting model, we need to replace the original file.

Accessible built-in variables and functions:

img

All of these variables can be found in the UnityDeferred file where they are declared.

Which rendering path to choose?

Unity's official documentation (A detailed comparison of the four rendering paths (forward rendering path, deferred rendering path, legacy deferred rendering path, and vertex illumination rendering path) is given in (http://docs./Manual/), including a comparison of their characteristics (whether they support pixel-by-pixel lighting, semi-transparent objects, real-time shadows, and so on), a comparison of their performances, and their platform support.

Overall, we need to choose a render path based on the target platform the game is being released on. If the current graphics card does not support the selected render path, then Unity will automatically use a render path one level below it.