In HDRP you still can’t “feed a CommandBuffer into Shader Graph”, but you can feed GPU data that your graph reads. For “an array says which face should be colored”, the cleanest Shader-Graph-friendly solution is:
Shader Graph can easily sample a texture, but it’s awkward to index arbitrary CPU arrays directly. So you:
- store a FaceID per face in the mesh (as a vertex attribute), and
- upload your per-face weather result into a 1D lookup texture (or 2D if you prefer), and
- in Shader Graph:
color = tex(FaceID).
If a vertex is shared by multiple faces, FaceID will interpolate / conflict.
So you need split vertices per face (like a flat-shaded mesh / hard edges). Many procedural meshes already do this; otherwise you may need to duplicate vertices so each triangle has unique vertices.
When building the mesh, write the same FaceID to all 3 vertices of the triangle (e.g. into uv2.x).
- FaceID range:
0 .. faceCount-1
- Store as float (fine up to ~16 million integer precision in float24 mantissa, but practically you’re safe for typical mesh sizes)
Use width = faceCount, height = 1.
- If you just need “color this face or not”:
R8 or RFloat
- If you need an actual color per face:
RGBA32 / RGBAHalf / RGBAFloat
C# (mask example, 0..1 per face)
int faceCount = triangleCount; // one value per triangle
var tex = new Texture2D(faceCount, 1, TextureFormat.RFloat, false, true);
tex.filterMode = FilterMode.Point;
tex.wrapMode = TextureWrapMode.Clamp;
float[] faceMask = new float[faceCount]; // fill from your weather system
tex.SetPixelData(faceMask, 0);
material.SetTexture("_FaceMaskTex", tex);
material.SetFloat("_FaceMaskTexWidth", faceCount);
For frequent updates, keep the texture and call SetPixelData + Apply(false,false) when data changes.
In Shader Graph:
- Add a Texture2D property:
_FaceMaskTex
- Add a Float property:
_FaceMaskTexWidth
- Read FaceID from your chosen attribute:
- If you stored in UV2.x, use UV node set to UV2, take X
- Convert FaceID → texture U coordinate:
u = (FaceID + 0.5) / _FaceMaskTexWidth
v = 0.5
Then:
- Use Sample Texture 2D (set Sampler State to Point/Clamp if you expose it, or set on the texture as above)
- Use sampled
R as mask, then Lerp(BaseColor, WeatherColor, mask)
That gives you a per-face weather-driven color.
If you want to avoid duplicating vertices / storing FaceID, the “ideal” way is to index by SV_PrimitiveID (triangle ID) and read a StructuredBuffer. But Shader Graph doesn’t make PrimitiveID + StructuredBuffer indexing painless; it typically requires a custom HLSL shader or more advanced HDRP customization (custom pass / hand-written shader).
So unless you’re already comfortable dropping to HLSL, the data texture + FaceID attribute is the most practical in Shader Graph.
- ✅ Do faces change color “randomly” near edges? → you have shared vertices; you need split vertices per face.
- ✅ Are you seeing blurred values? → ensure Point filtering and correct
(FaceID + 0.5)/width addressing.
- ✅ Need multiple weather values per face (wetness, snow, heat)? → pack into RGBA channels.
If you tell me whether your “face should be colored” data is binary (yes/no) or a full color, and roughly how many faces you’re targeting (hundreds / thousands / 100k), I’ll recommend the best texture format + update strategy (CPU update vs compute).