Skip to content

t1k:unity:rendering:shader-graph

FieldValue
Modulerendering
Version3.1.7
Efforthigh
Tools

Keywords: shader graph, shaders, unity, visual shader

/t1k:unity:rendering:shader-graph

URP ONLY — All shaders must target URP. Never create Built-in RP or HDRP shaders. Prerequisite: see unity-urp (pipeline config, render features, forward+/deferred).

Use Code (.shader)Use Shader Graph (.shadergraph)
Custom semantics (vertex COLOR, TEXCOORD2)Artist-friendly, node-based
Precise pass control (ShadowCaster, DepthOnly)Quick prototyping
SRP Batcher critical pathSub Graphs for reuse
Performance-critical terrain/particlesPreview mode in editor

This project uses code-based shaders — see VertexColorTerrain.shader as the canonical example.

Shader "Namespace/ShaderName" {
Properties { _BaseMap ("Texture", 2D) = "white" {} }
SubShader {
Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" "Queue"="Geometry" }
Pass { Name "ForwardLit" Tags { "LightMode" = "UniversalForward" }
HLSLPROGRAM
#pragma vertex vert #pragma fragment frag
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _SHADOWS_SOFT
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap);
CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; CBUFFER_END
// Attributes → vert → Varyings → frag
ENDHLSL }
// ShadowCaster + DepthOnly passes required for full URP support
}
}
struct Attributes { float4 positionOS : POSITION; float4 color : COLOR; };
struct Varyings { float4 positionCS : SV_POSITION; float4 vertexColor : TEXCOORD2; };
Varyings vert(Attributes IN) {
Varyings OUT;
OUT.positionCS = GetVertexPositionInputs(IN.positionOS.xyz).positionCS;
OUT.vertexColor = IN.color;
return OUT;
}
half4 frag(Varyings IN) : SV_Target { return half4(IN.vertexColor.rgb, 1.0); }
  • All non-texture properties must be inside CBUFFER_START(UnityPerMaterial) / CBUFFER_END
  • CBUFFER must be identical across all passes (ForwardLit, ShadowCaster, DepthOnly)
  • Textures go outside the CBUFFER: TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap);
  • Missing a property from any pass breaks SRP Batcher compatibility
PassLightMode TagPurpose
ForwardLitUniversalForwardMain rendering
ShadowCasterShadowCasterCast shadows
DepthOnlyDepthOnlyCamera depth texture
DepthNormalsDepthNormalsSSAO support

GPU Instancing (DrawMeshInstancedProcedural)

Section titled “GPU Instancing (DrawMeshInstancedProcedural)”
struct InstanceData { public Matrix4x4 matrix; public Vector4 color; }
ComputeBuffer _buffer;
void OnEnable() {
_buffer = new ComputeBuffer(count, Marshal.SizeOf<InstanceData>());
_buffer.SetData(data); _material.SetBuffer("_InstanceBuffer", _buffer);
}
void Update() => Graphics.DrawMeshInstancedProcedural(_mesh, 0, _material, bounds, count);
void OnDisable() { _buffer?.Release(); _buffer = null; } // MANDATORY — GPU leak if skipped

→ See references/urp-shader-code-guide.md for ShadowCaster, DepthOnly, PBR fragment, vertex semantics.

var shader = Shader.Find("DOTSBattlefield/VertexColorTerrain");
var mat = new Material(shader);
mat.SetTexture("_BaseMap", myTexture);
AssetDatabase.CreateAsset(mat, "Assets/Generated/MyMat.mat");
AssetDatabase.SaveAssets();

→ See references/shader-graph-nodes-guide.md for Shader Graph node categories, Custom Function node, Sub Graphs, Blackboard properties, and Vertex Color in Shader Graph.

  • URP Lit ignores vertex colorsUniversal Render Pipeline/Lit does NOT read COLOR semantic; always use a custom shader for vertex-colored meshes
  • Shader.Find returns null — shader not yet imported; run Assets > Reimport All; shader must be in Assets/ or Packages/, never in Editor/
  • Don’t use UsePass — breaks SRP Batcher; redefine each pass inline
  • Surface Shaders unsupported in URP — rewrite as vertex/fragment HLSL
  • _TextureName_ST in CBUFFER — must be declared even if unused (SRP Batcher requirement)
  • StructuredBuffer = SRP Batcher incompatible — add "DisableBatching" = "True" tag for instanced draws
  • URP predefines math-constant macros (TWO_PI, PI, HALF_PI, FOUR_PI, INV_PI, …) via Core.hlslMacros.hlsl. Redeclaring one, e.g. static const float TWO_PI = 6.28;, preprocessor-expands to static const float 6.283... = 6.28; → cryptic syntax error: unexpected float constant. Use a prefixed name (GRASS_TWO_PI) or just use URP’s macro. isSupported can lie (stale ShaderCache) — read ShaderUtil.GetShaderMessages for the real errors. → references/hlsl-macro-and-keyword-traps.md
  • shader_feature_local variants get stripped from player builds unless an on-disk material enables the keyword at build time. A runtime-only material.EnableKeyword("_KW") on a new Material(base) clone → variant dropped → feature silently no-ops in the player (works in editor, which compiles all variants on demand). For runtime-toggled keywords use #pragma multi_compile_local _ _KW instead. Verify in a built player, not just the editor. → references/hlsl-macro-and-keyword-traps.md
FileContents
references/urp-shader-code-guide.mdFull HLSL structure, CBUFFER, vertex semantics, fragment (Unlit/Lit/PBR), ShadowCaster, DepthOnly, URP includes
references/shader-graph-nodes-guide.mdShader Graph creation, Master Stack, node categories, Custom Function, Sub Graphs, Blackboard
references/hlsl-macro-and-keyword-traps.mdHand-written HLSL traps: URP math-constant macro collisions (TWO_PI etc. → unexpected float constant), shader_feature_local variant stripping in player builds (use multi_compile_local for runtime toggles)