Using Renderer Shader User Value (RSUV), introduced in Unity 6.3, allows setting unique properties per renderer, to be used in their material shaders, with no performance cost when using the SRP Batcher (and GPU Resident Drawer).
The RSUV is a uint (32 bit unsigned integer), which requires packing data on the C# renderer side, and unpacking data on the HLSL shader side.
While packing and unpacking data is trivial, the RSUV Bit Packer (package) aims at providing a user friendly workflow to design packing scheme and set Renderer Properties in the Editor or from a C# script.
- Open the Package Manager, click on the + Icon, select "Add Package from Git Url".
- Enter the package url:
git@github.com:FredMoreau/RSUV-Bit-Packer.git, orhttps://github.com/FredMoreau/RSUV-Bit-Packer.git
- Enter the package url:
- Or clone the repo, select "Add Package from disk" and select the
package.jsonfile. - Or download as a zip, and unzip it in your project's Packages folder.
Then install the Samples.
The package allows you to define a packing scheme by adding "Renderer Properties", easily changing precision to fit in the 32 bits, then pack those properties and assign them to Renderers's RSUV and eventually fetch the properties' values in Shader Graph, using:
- a Property Sheet (asset) that eventually generates a Shader Include using the new Shader Function Reflection API to fetch the data in Shader Graph.
- a Property Packer (component) that sets the value on renderers and exposes properties to Animation, C# and even Visual Scripting.
Create a new Property Sheet using Assets/Create/Rendering/RSUV Bit Packer/Property Sheet.
This asset allows defining a packing scheme to be reused with several Property Packers later.
Properties values serve as default values when assigning the sheet to a Packer component, and as preview values in Shader Graph.
Some properties are fixed sized, like the Boolean Property which will only use one bit. Other properties feature settings that allows adjusting their size, like the Scalar Property that features a precision setting.
At the top of a Renderer Property List, the Help Box displays how many bits are used, and the Add Menu grays out the fixed size properties that cannot fit.
If the properties exceed the capacity, the Help Box turns into a warning, and any property that doesn't fit turns red.
The Property Sheet also allows generating a Shader Include (HLSL) to access the properties in Shader Graph.
If the "Split Functions" option is enabled, it'll generate one function per property, otherwise it'll generate one function for all properties.
In Unity 6.3 and 6.4, Shader Includes are generated using the Shader Graph Custom Function syntax for them to be used with Custom Function Nodes.
In Unity 6.5, Shader Includes are generated using the Shader Function Reflection API syntax, which makes them automatically accessible in Shader Graph without having to manually configure a Custom Function Node.
Note: in Unity 6.5, to avoid potential collision with other HLSL functions, generated Shader Includes are namespaced, using the Assembly Definition namepace the hlsl file belongs to, if any, or the Project's root namespace.
Add a Property Packer to a GameObject using Component/Rendering/RSUV Bit Packer/Property Packer, and assign the Renderers it shall set the RSUV to.
For quick prototyping, the list of Renderer Properties can be defined in the component itself, and some generic shader functions are provided to fetch them in Shader Graph, providing the bit offset.
Assigning a Property Sheet on a Property Packer will make it inherit the properties from the sheet. Which allows using the same Property Sheet with several Property Packers for consistency. If the property sheet is further edited, the Packers will display a warning and a button to update their properties.
Properties are packed and set on the renderer when modified and/or animated in the Editor and at Runtime.
The API PropertyPacker.TrySetProperty() allows setting properties from C# at Runtime.
Note, it is good practice to store a property index using PropertyPacker.GetPropertyIndex(string propertyName) and use PropertyPacker.TrySetProperty(int index, value).
It is also preferred to use the generic method PropertyPacker.TrySetProperty<T>(int index, T value).
The main purpose of the non generic PropertyPacker.TrySetProperty(int index, object value) is for Visual Scripting support.
For the PropertyPacker component's methods to appear in Visual Scripting, Unity.RSUVBitPacker must be added to the Node Library in Project Settings/Visual Scripting.
A boolean value stored on one bit.
An integer value stored with custom precision. The length determines the maximum value. E.g.: 4 bits = max value 15, 5 bits = max value 31.
A float value stored with custom precision.
Similar to int but displays as a dropdown. The precision depends on the number of entries. E.g.: 2 entries = 1 bit, 3-4 entries = 2 bits, 5-8 entries = 3 bits, and so on.
Stores a color over 24 bits (8 bits per channel).
Stores a color over variable precision per HSV channels. If the saturation or value precision is set to 0, it defaults to one.
A Color Palette is an asset that allows defining colors and generating an HLSL Shader Include.
The generated HLSL allows getting a color from the palette in Shader Graph.
To install samples, go to the Package Manager, select the package in the list and go to the Samples tab.
The Samples use TextMeshPro. If no text appear in the scenes, go to Window/TextMeshPro/Import TMP Essential Resources.
Some examples use OnMouseEnter() and OnMouseExit(), which only work with the (new) Input System in Unity 6.4 and above.
This contains several examples of the different Renderer Properties.
This contains:
- a custom "Enum Color" Renderer Property, storing an index to a Color Array.
- a custom "Power Scalar" Renderer Property, applying a power on the packed data to bias precision toward low range values.
This contains an example of setting a Renderer Property on a Property Packer from Visual Scripting.
RSUV being implemented only on some Renderer classes, such as MeshRenderer and SkinnedMeshRenderer, this package contains an Extension that makes it easy to set the ShaderUserValue on a Renderer.
2D Renderers (Sprite, SpriteShape and Tilemap) are supported in Unity 6.5 and above, as well as in 6.3.13, but not yet in 6.4.
The package is easily extensible to add new Renderer Property types by simply providing their data encoding (C#) and decoding (HLSL).
One can be created from template using Assets/Create/Scripting/RendererProperty.
using UnityEngine.RSUVBitPacker;
// RendererValue Attributes are used by the PropertyList.
[System.Serializable]
[RendererValueTypeName("NewRendererProperty")] //The name of the 'Add' Dropdown MenuItem.
//[RendererValueTypeLength(1)] // If used, the MenuItem will be grayed out if the length is greater than remaining bits available.
[RendererValueTypeTooltip("A single bit storing a boolean value.")] //
public class NewRendererProperty : RendererProperty<bool> // the type defines the serialized value type
{
// This is used to offset bitshift index.
public override uint Length => 1;
// This is expected to provide the data, as a uint, of which only the first n bits are used.
public override uint Data => Value ? 1u : 0u;
// The next two overrides are not mandatory. They are used by the HLSL generator.
// If left unoverriden, the property value will not be featured in the generated Shader Include.
// This is used to write the 'out' parameter.
public override string HlslType => "bool";
// This is used to write the parameter assignment in the shader function body.
// rsuv is short for unity_RendererUserValue.
// paramName is the name of the property as set by the user.
// bitIndex is where the data storage begins in the rsuv uint.
public override string HlslDecoder(string paramName, uint bitIndex) => $"{paramName} = (rsuv & (1 << {bitIndex})) != 0;";
}
There is no check on property names other than whitespace removal and default naming if left empty. Don't give several properties the same name, and don't name properties with HLSL types or intrisic functions like "float" or "dot".
Previews in Shader Graph use the default values set in the Property Sheet. Future improvement may add a Preview Value to the Nodes' settings.
Considered for future improvement to add an interface for MonoBehaviours to provide renderer properties.













