Intro
Each GameObject in my scene is given a unique ID, and I want this ID value to be used inside the Shader that is part of the Material of every GameObject in my scene.
Specifically, I want this identifier to be able to be stored in a Color channel, i.e. it has to be a float between 0 and 1 that is unique to every GameObject in the scene.
Architecture
In the following 3 sections I outline the 3 main scripts I used for this post.
They interact as follows:
- My Identification script is attached to each GameObject in the scene that I want to attribute to an unique ID.
- This Identification script calls a function from the script IDManager (which I have attached to another GameObject in my scence) to get a unique ID.
- Then, the Identification script creates a MaterialPropertyBlock object to which it assigns the ID.
- Finally, in my Shader which I assign to the material associated with a custom Render Objects Render Feature, I can read this ID value from the MaterialPropertyBlock to then return it in the red color channel in the fragment shader.
IDManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/**
* The first id starts at 0.0001.
* We don't use 0 because that's reserved for the background.
*/
public class IDManager : MonoBehaviour
{
public static IDManager instance; // Singleton instance
private int lastAssignedID = 0; // Keep track of last assigned ID
private int totalObjects = 10000; // Total number of objects you expect
void Awake()
{
// Singleton setup
if (instance == null)
{
instance = this;
DontDestroyOnLoad(gameObject); // Ensure the manager persists between scenes
}
else
{
Destroy(gameObject);
}
}
public float GetUniqueID()
{
lastAssignedID += 1;
return (float)lastAssignedID / totalObjects; // Normalize the ID
}
}
Identification
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Identification : MonoBehaviour
{
private float _id;
private Renderer _renderer;
private MaterialPropertyBlock _propBlock;
void Awake()
{
_id = IDManager.instance.GetUniqueID();
_propBlock = new MaterialPropertyBlock();
_renderer = this.gameObject.GetComponent<Renderer>();
// TEMP
Debug.Log("ID: " + _id);
_renderer.GetPropertyBlock(_propBlock);
_propBlock.SetFloat("_ID", _id);
_renderer.SetPropertyBlock(_propBlock);
}
}
URP Shader
Shader "Custom/UniqueColor2"
{
Properties
{
_ID ("ID", Range(0, 1)) = 0.01
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
float _ID;
CBUFFER_END
struct VertexInput
{
float4 position : POSITION;
};
struct VertexOutput
{
float4 position : SV_POSITION;
};
ENDHLSL
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
VertexInput vert(VertexInput v)
{
VertexInput o;
o.position = TransformObjectToHClip(v.position.xyz);
return o;
}
float4 frag(VertexOutput i) : SV_Target
{
return float4(_ID, 0, 0, 1);
}
ENDHLSL
}
}
}
Top comments (0)