🍡

Material System

Tags

Composition

The shader programs are compiled as a single unit, but there are multiple functionality that needs to be combined together.

Vertex transformation, vertex blending, morphing, tessellation, instancing, and other operations are distinct from surface shading but they need to be executed together when drawing meshes.

A material system is responsible for composing surface shading with geometry processing.

The compositing of multiple functionality can be done at compile-time and at run-time.

Some functionality can be selected at run-time using dynamic branching.

However, when using large shaders with branches that are rarely taken, the lower register occupancy reduce performance.

Another solution is to perform the composition at the source code level by building shader variants.

Multiple shader variants are generated using preprocessor directives (symbols and conditionals).

However, it can produce a large number of shader variants.

A modern material system will use both strategies depending on the functionalities.

Modularity and composability of shader source code is critical.

There are different strategies to write modular shader code.

Optimizations

Frequency

Uniform parameters should be grouped by the frequency of their update.

Application

Computations that are constant over the lifetime of the application can be computed on the GPU once and passed as uniform parameters.

For example, the start time.

Per Frame

The view and projection matrices can be calculated and passed as a combined transformation.

Per Model

The lighting parameters are constant for a specific location.

Per Draw Call

The material parameters are specific to each draw call.

A material system can detect the computations that are constant within a draw call, and move them outside of the shader.

Within a Draw Call

Fragment shaders are evaluated more often than vertex shaders.

Some computations can be computed in earlier shader stages, and passed down to other stages as varying data to reduce the number of computations in more expensive shader stages.