New in 6.3: Renderer Shader User Value (RSUV)
History
In certain scenarios, games may need to manage a large number of objects (e.g., MeshRenderers) while applying unique visual customization to each instance. Prior to the introduction of the Scriptable Render Pipeline (SRP), the most efficient method for achieving this was through the use of Material Property Blocks (MPBs).
With the advent of the SRP Batcher, however, a more performant approach has been to generate a dedicated Material for each customized renderer. This method has demonstrated significantly better runtime performance compared to MPBs.
Nevertheless, in many cases the required customization per object is limited to only a small set of parameters. While duplicating the entire Material for each object is a nice and simple solution, a more focused and efficient alternative can now be employed.
Renderer Shader User Value (RSUV)
In Unity 6.3, we introduced a small yet powerful feature accessible via the MeshRenderer and SkinnedMeshRenderer APIs:
MeshRenderer.SetShaderUserValue(uint value);
SkinnedMeshRenderer.SetShaderUserValue(uint value);
This API enables the assignment of a custom 32-bit unsigned integer value to each renderer. The value is accessible within shader HLSL code through the unity_RendererUserValue property. Importantly, this functionality introduces no additional CPU overhead and does not interfere with batching.
The primary advantage of this approach is that all customized renderers continue to share a single Material. As a result, in most scenarios it yields a notable performance improvement (see the Performance section below).
Note: From the shader side, the RSUV value can be easily accessed within Shader Graph by means of a custom HLSL node.
Use case and ideas
At first glance, a 32-bit value may seem insufficient for customizing visuals on a per-renderer basis. However, the unity_RendererUserValue (RSUV) can be applied flexibly in a variety of scenarios. Examples include:
Note: RSUV usage and encoding are shader-specific. For instance, one shader might interpret the RSUV as a color, while another may treat it as an index into auxiliary data. The potential applications are numerous, even when utilizing just a single 32-bit value.
Performance
Benchmark project
While theoretical considerations are useful, performance measurements provide the most reliable insight on the value of the feature.
To this end, we conducted a test project involving 900 MeshRenderers. Each renderer was assigned a unique color and scale value. Performance was evaluated by averaging the CPU profiler marker RenderLoop.DrawSRPBatcher, measured in milliseconds. It is important to note that this metric reflects only the CPU rendering workload, not the total frame time.
Note: To better approximate a real-world game scenario, a new sphere mesh was instantiated every 10 objects, effectively simulating the presence of a new mesh model at this interval.
The benchmark scene is shown below, where each object exhibits a randomized color and scale:
We evaluated four methods to achieve the desired customization:
- Material Property Block (MPB):
A Shader Graph was configured to use a Vector4 for color and a float for uniform scale. At initialization, each renderer was assigned a unique MPB containing randomized color and scale values. - Multiple Materials (MM):
At initialization, a distinct Material was instantiated for each renderer, with each Material containing a unique color and scale value. - GPU Resident Drawer (GRD) with Multiple Materials:
Identical to the Multiple Materials method, but with GRD enabled. - Renderer User Value (RSUV):
At initialization, a unique RSUV value was assigned to each renderer using the new API. The value holds 24 bits for RGB color and 8 bits for uniform scale. A Shader Graph, extended with a custom HLSL node, was used to decode the RSUV value. GRD was disabled in this configuration. - GRD + RSUV:
Same as the RSUV method above, but with GRD enabled.
We begin by comparing the timing results of the legacy MPB approach against the standard SRP Batcher Multiple Materials method.
Note: The use of Material Property Blocks (MPBs) is notably inefficient in this particular scenario, as we are dealing with 900 individual renderers, each requiring two unique custom values, as this creates a large amount of batches. The performance disadvantage would be less significant if multiple renderers shared the same color or scale values. Nonetheless, it is important to emphasize that MPBs generally offer lower performance compared to using separate materials, especially since the introduction of the SRP Batcher.
Let us now set aside the legacy MPB approach and concentrate on the four alternative methods:
As a timing chart should always be accompanied by an explanation, here are some technical details regarding the reported numbers:
-
MM
(Multiple Materials): 1.42 ms serves as the baseline, where each renderer uses a unique material. -
GRD+MM
When enabling GRD, one might expect a significant performance improvement. However, in this contextâwhere each renderer has a different material (to allow for random color assignments)âthis represents the worst-case scenario for GRD. GPU instancing cannot be utilized, resulting in one draw call per object, in addition to the overhead of switching materials between objects. Nevertheless, GRD+MM still beats MM, with a rendering time of 1.26 ms. -
RSUV
Achieving a time of 1.08 ms, RSUV is faster than GRD+MM. This is because, unlike GRD+MMâwhich incurs both draw call and material switching costs per objectâRSUV does not require separate materials and therefore avoids the material switching overhead. -
GRD+RSUV
This combination yields the best results. Since RSUV does not require different materials, it allows GRD to fully optimize draw calls (in this scene, one draw call can handle 10 objects). Individual object customization with random values is still possible, while obtaining the maximum performance benefits from GRD.
As a result, we achieved an impressive 5x performance increase with the combination of GRD and RSUV compared to the baseline MM approach!
Last note
We designed the RSUV feature to introduce no additional CPU overhead. To demonstrate this, we modified our benchmark scene so that no per-renderer customization was appliedâall spheres shared the same color and size. Under these conditions, the classic SRP Batcher executed in 1.09 ms. If we disregard performance measurement jitter, its performance matches that of RSUV alone.
Under the same conditions, GRD rendered in 0.27 ms, identical to the performance of GRD combined with RSUV.
These results clearly demonstrate that RSUV enables per gameobject shader customization with virtually no additional CPU overhead.



