urp-hlsl-templates について
Unity の Universal Render Pipeline 向けに、HLSL と ShaderLab のコードベースのシェーダー作成を支援するスキルです。URP テンプレート、移行ガイド、互換性や描画に関する注意点をまとめています。
主な機能
- 01URP の Unlit・Lit テンプレート
- 02Built-in から URP への移行資料
- 03SRP Batcher と HLSL の規約
- 04パスとシェーダーバリアントの指針
活用シーン
- 01コードで URP シェーダーを作成
- 02Built-in パイプラインのシェーダーを URP に移行
- 03URP シェーダーのよくある問題を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ adevra/ unity-shader-agent-skills --skill urp-hlsl-templatesインストール後、Claude Code で/urp-hlsl-templatesを入力して読み込まれたか確認します。
詳細
URP HLSL シェーダーコードテンプレート
トリガー
ユーザーが Universal Render Pipeline 用の HLSL/ShaderLab コード(Shader Graph ではない)で Unity シェーダーを書きたい場合に、このスキルを使用します。トリガーには、「URP shader」、「HLSL」、「ShaderLab」、「write a shader」、「custom shader」、「vertex fragment shader」、「SRP Batcher」、「CBUFFER」、「custom lit shader」、「unlit shader」、または URP でコードを使ってシェーダーを作成するあらゆるケースが含まれます。Built-in パイプラインのシェーダーを URP に変換する場合や、ユーザーが Cyanilux のテンプレート、phi-lira の gist、NedMakesGames のチュートリアルに言及した場合も対象です。
基本ルール — URP HLSL
-
必ず
HLSLPROGRAM/ENDHLSLを使用し、CGPROGRAM/ENDCGは使用しないでください。 URP は CG ではなく HLSL を使用します。CG ブロックはコンパイルできますが、URP 固有のインクルードやマクロが適用されません。 -
SRP Batcher との互換性を保つため、すべてのマテリアルプロパティを
CBUFFER_START(UnityPerMaterial)/CBUFFER_ENDブロック内に記述してください。 これを行わないと、マテリアルごとにバッチ処理が妨げられ、個別のドローコールが発生します。 -
レガシーな Unity のインクルードではなく、URP Core をインクルードしてください。
// CORRECT (URP) #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" // WRONG (Built-in / legacy) #include "UnityCG.cginc" #include "Lighting.cginc" -
レガシーなものではなく、URP の変換マクロを使用してください。
// URP // Legacy equivalent TransformObjectToHClip(posOS) // UnityObjectToClipPos(v.vertex) TransformObjectToWorld(posOS) // mul(unity_ObjectToWorld, v.vertex) TransformObjectToWorldNormal(nOS) // UnityObjectToWorldNormal(v.normal) TransformWorldToHClip(posWS) // mul(UNITY_MATRIX_VP, float4(posWS, 1)) GetVertexPositionInputs(posOS) // (convenience struct) GetVertexNormalInputs(nOS, tanOS) // (convenience struct) -
タグに
"RenderPipeline" = "UniversalPipeline"を含めてください。 含めないと、シェーダーは URP に認識されません。 -
sampler2Dではなく、TEXTURE2DとSAMPLERのマクロを使用してください。TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); // Sample with: half4 col = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv);
テンプレート:URP アンリット(モバイル対応)
SRP Batcher 互換の最小限のアンリットシェーダーです。モバイルシェーダーの出発点として使用してください。
Shader "Custom/URP_Unlit_Mobile"
{
Properties
{
_BaseMap ("Base Map", 2D) = "white" {}
_BaseColor ("Base Color", Color) = (1, 1, 1, 1)
}
SubShader
{
Tags
{
"RenderType" = "Opaque"
"RenderPipeline" = "UniversalPipeline"
"Queue" = "Geometry"
}
Pass
{
Name "ForwardLit"
Tags { "LightMode" = "UniversalForward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
// SRP Batcher compatible: all properties in CBUFFER
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
half4 _BaseColor;
CBUFFER_END
TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
half fogFactor : TEXCOORD1;
};
Varyings vert(Attributes input)
{
Varyings output;
VertexPositionInputs posInputs = GetVertexPositionInputs(input.positionOS.xyz);
output.positionCS = posInputs.positionCS;
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
output.fogFactor = ComputeFogFactor(posInputs.positionCS.z);
return output;
}
half4 frag(Varyings input) : SV_Target
{
half4 color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv) * _BaseColor;
color.rgb = MixFog(color.rgb, input.fogFactor);
return color;
}
ENDHLSL
}
// Shadow caster pass (required for objects to cast shadows)
Pass
{
Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
ZWrite On ZTest LEqual ColorMask 0
HLSLPROGRAM
#pragma vertex ShadowPassVertex
#pragma fragment ShadowPassFragment
#include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl"
ENDHLSL
}
// Depth pass (required for depth-based effects)
Pass
{
Name "DepthOnly"
Tags { "LightMode" = "DepthOnly" }
ZWrite On ColorMask R
HLSLPROGRAM
#pragma vertex DepthOnlyVertex
#pragma fragment DepthOnlyFragment
#include "Packages/com.unity.render-pipelines.universal/Shaders/DepthOnlyPass.hlsl"
ENDHLSL
}
}
Fallback "Universal Render Pipeline/Unlit"
}
テンプレート:メインライトを使う URP リット
メインのディレクショナルライトによるランバート拡散照明を追加します。
Shader "Custom/URP_SimpleLit_Mobile"
{
Properties
{
_BaseMap ("Base Map", 2D) = "white" {}
_BaseColor ("Base Color", Color) = (1, 1, 1, 1)
}
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
#pragma multi_compile_fog
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
half4 _BaseColor;
CBUFFER_END
TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float3 normalWS : TEXCOORD1;
float3 positionWS : TEXCOORD2;
half fogFactor : TEXCOORD3;
};
Varyings vert(Attributes input)
{
Varyings output;
VertexPositionInputs posInputs = GetVertexPositionInputs(input.positionOS.xyz);
VertexNormalInputs normInputs = GetVertexNormalInputs(input.normalOS);
output.positionCS = posInputs.positionCS;
output.positionWS = posInputs.positionWS;
output.normalWS = normInputs.normalWS;
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
output.fogFactor = ComputeFogFactor(posInputs.positionCS.z);
return output;
}
half4 frag(Varyings input) : SV_Target
{
half4 baseColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv) * _BaseColor;
// Main light (directional)
float4 shadowCoord = TransformWorldToShadowCoord(input.positionWS);
Light mainLight = GetMainLight(shadowCoord);
half3 normal = normalize(input.normalWS);
half NdotL = saturate(dot(normal, mainLight.direction));
half3 diffuse = baseColor.rgb * mainLight.color * NdotL * mainLight.shadowAttenuation;
// Ambient
half3 ambient = SampleSH(normal) * baseColor.rgb;
half3 finalColor = diffuse + ambient;
finalColor = MixFog(finalColor, input.fogFactor);
return half4(finalColor, baseColor.a);
}
ENDHLSL
}
// Include ShadowCaster and DepthOnly passes (same as unlit template above)
UsePass "Custom/URP_Unlit_Mobile/ShadowCaster"
UsePass "Custom/URP_Unlit_Mobile/DepthOnly"
}
Fallback "Universal Render Pipeline/Simple Lit"
}
Built-in → URP 変換チートシート
| Built-in | URP の対応表現 |
|---|---|
#include "UnityCG.cginc" | #include ".../Core.hlsl" |
#include "Lighting.cginc" | #include ".../Lighting.hlsl" |
UnityObjectToClipPos(v) | TransformObjectToHClip(v.xyz) |
UnityObjectToWorldNormal(n) | TransformObjectToWorldNormal(n) |
_WorldSpaceLightPos0 | GetMainLight().direction |
_LightColor0 | GetMainLight().color |
UNITY_LIGHTMODEL_AMBIENT | SampleSH(normal) |
SHADOW_COORDS / TRANSFER_SHADOW | TransformWorldToShadowCoord(posWS) |
SHADOW_ATTENUATION(i) | GetMainLight(shadowCoord).shadowAttenuation |
tex2D(_Tex, uv) | SAMPLE_TEXTURE2D(_Tex, sampler_Tex, uv) |
sampler2D _Tex | TEXTURE2D(_Tex); SAMPLER(sampler_Tex); |
UNITY_FOG_COORDS / APPLY_FOG | ComputeFogFactor() / MixFog() |
v2f struct convention | Varyings struct convention |
appdata struct convention | Attributes struct convention |
Tags { "LightMode" = "ForwardBase" } | Tags { "LightMode" = "UniversalForward" } |
Surface shader #pragma surface | 対応する機能なし — 頂点/フラグメントを手動で記述 |
マルチパスと追加パス
URP がパスを認識するには、明示的なパス名が必要です。
| LightMode タグ | 用途 |
|---|---|
UniversalForward | メインのレンダリングパス |
ShadowCaster | シャドウマップの生成 |
DepthOnly | 深度プリパス |
DepthNormals | 深度+法線のプリパス(SSAO、深度・法線エフェクト用) |
Meta | ライトマップのベイク |
Universal2D | 2D レンダラーのパス |
SRPDefaultUnlit | LightMode が一致しない場合のフォールバック |
よくある落とし穴
-
CBUFFER の記述忘れ → SRP Batcher が機能しなくなります。各ドローコールが個別扱いになります。Frame Debugger の「SRP Batcher」列で確認してください。
-
TEXTURE2Dマクロではなくsampler2Dを使用する → 動作はしますが、クロスプラットフォームのサンプラー制御が失われ、一部のプラットフォームで問題が発生することがあります。 -
ShadowCaster パスの不足 → オブジェクトが影を落とさなくなります。必ず追加するか、
UsePass/Fallbackを使用してください。 -
DepthOnly パスの不足 → 深度ベースのエフェクト(フォグ、ポストプロセッシング、水深)は、このオブジェクトを認識できません。
-
shader_featureではなくmulti_compileを使用する →multi_compileはすべてのキーワードバリアントをコンパイルします。shader_featureは、ビルド内のマテリアルで使用されるバリアントのみをコンパイルします。マテリアル固有の切り替えには、必ずshader_featureを使用してください。
参考リポジトリと Gist
- Cyanilux URP コードテンプレート(CC0)— https://github.com/Cyanilux/URP_ShaderCodeTemplates
- Cyanilux URP シェーダーコードチュートリアル — https://www.cyanilux.com/tutorials/urp-shader-code/
- phi-lira URP Lit テンプレート — https://gist.github.com/phi-lira/225cd7c5e8545be602dca4eb5ed111ba
- NedMakesGames の URP HLSL 9 部構成シリーズ — https://nedmakesgames.medium.com/
- ハーフトーン Toon URP Gist — https://gist.github.com/wonkee-kim/3b5c1821975b8414f420f93ef6cdf5a0
- ワイドアウトライン URP Gist — https://gist.github.com/ScottJDaley/6cddf0c8995ed61cac7088e22c983de1
- Toon Shader URP 11 Gist — https://gist.github.com/FaultyPine/08306e52971d77081ea159128cb3e5b5
- URP カスタム Lit BlinnPhong — https://gist.github.com/xCyborg/2923ce9e57e65af9d417706dda4db4be
- ColinLeung-NiloCat URP Toon Lit — https://github.com/ColinLeung-NiloCat/UnityURPToonLitShaderExample
出典
- Cyanilux:URP シェーダーコードテンプレート — https://github.com/Cyanilux/URP_ShaderCodeTemplates
- NedMakesGames:コードで URP シェーダーを書く — https://nedmakesgames.medium.com/
- Catlike Coding:カスタム SRP — https://catlikecoding.com/unity/tutorials/
- Daniel Ilett:Shader Graph + HLSL — https://danielilett.com/
- ColinLeung-NiloCat:モバイル URP Toon — https://github.com/ColinLeung-NiloCat/UnityURPToonLitShaderExample
- Unity:シェーダーのパフォーマンス — https://docs.unity3d.com/Manual/SL-ShaderPerformance.html