mcpField
U
urp-hlsl-templates

urp-hlsl-templates

github.com/adevra開発1654 回インストール31 週間前に更新
リポジトリ

urp-hlsl-templates について

Unity の Universal Render Pipeline 向けに、HLSL と ShaderLab のコードベースのシェーダー作成を支援するスキルです。URP テンプレート、移行ガイド、互換性や描画に関する注意点をまとめています。

主な機能

  1. 01URP の Unlit・Lit テンプレート
  2. 02Built-in から URP への移行資料
  3. 03SRP Batcher と HLSL の規約
  4. 04パスとシェーダーバリアントの指針

活用シーン

  1. 01コードで URP シェーダーを作成
  2. 02Built-in パイプラインのシェーダーを URP に移行
  3. 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

  1. 必ず HLSLPROGRAM/ENDHLSL を使用し、CGPROGRAM/ENDCG は使用しないでください。 URP は CG ではなく HLSL を使用します。CG ブロックはコンパイルできますが、URP 固有のインクルードやマクロが適用されません。

  2. SRP Batcher との互換性を保つため、すべてのマテリアルプロパティを CBUFFER_START(UnityPerMaterial)/CBUFFER_END ブロック内に記述してください。 これを行わないと、マテリアルごとにバッチ処理が妨げられ、個別のドローコールが発生します。

  3. レガシーな 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"
    
  4. レガシーなものではなく、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)
    
  5. タグに "RenderPipeline" = "UniversalPipeline" を含めてください。 含めないと、シェーダーは URP に認識されません。

  6. 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-inURP の対応表現
#include "UnityCG.cginc"#include ".../Core.hlsl"
#include "Lighting.cginc"#include ".../Lighting.hlsl"
UnityObjectToClipPos(v)TransformObjectToHClip(v.xyz)
UnityObjectToWorldNormal(n)TransformObjectToWorldNormal(n)
_WorldSpaceLightPos0GetMainLight().direction
_LightColor0GetMainLight().color
UNITY_LIGHTMODEL_AMBIENTSampleSH(normal)
SHADOW_COORDS / TRANSFER_SHADOWTransformWorldToShadowCoord(posWS)
SHADOW_ATTENUATION(i)GetMainLight(shadowCoord).shadowAttenuation
tex2D(_Tex, uv)SAMPLE_TEXTURE2D(_Tex, sampler_Tex, uv)
sampler2D _TexTEXTURE2D(_Tex); SAMPLER(sampler_Tex);
UNITY_FOG_COORDS / APPLY_FOGComputeFogFactor() / MixFog()
v2f struct conventionVaryings struct convention
appdata struct conventionAttributes struct convention
Tags { "LightMode" = "ForwardBase" }Tags { "LightMode" = "UniversalForward" }
Surface shader #pragma surface対応する機能なし — 頂点/フラグメントを手動で記述

マルチパスと追加パス

URP がパスを認識するには、明示的なパス名が必要です。

LightMode タグ用途
UniversalForwardメインのレンダリングパス
ShadowCasterシャドウマップの生成
DepthOnly深度プリパス
DepthNormals深度+法線のプリパス(SSAO、深度・法線エフェクト用)
Metaライトマップのベイク
Universal2D2D レンダラーのパス
SRPDefaultUnlitLightMode が一致しない場合のフォールバック

よくある落とし穴

  1. CBUFFER の記述忘れ → SRP Batcher が機能しなくなります。各ドローコールが個別扱いになります。Frame Debugger の「SRP Batcher」列で確認してください。

  2. TEXTURE2D マクロではなく sampler2D を使用する → 動作はしますが、クロスプラットフォームのサンプラー制御が失われ、一部のプラットフォームで問題が発生することがあります。

  3. ShadowCaster パスの不足 → オブジェクトが影を落とさなくなります。必ず追加するか、UsePass/Fallback を使用してください。

  4. DepthOnly パスの不足 → 深度ベースのエフェクト(フォグ、ポストプロセッシング、水深)は、このオブジェクトを認識できません。

  5. shader_feature ではなく multi_compile を使用する → multi_compile はすべてのキーワードバリアントをコンパイルします。shader_feature は、ビルド内のマテリアルで使用されるバリアントのみをコンパイルします。マテリアル固有の切り替えには、必ず shader_feature を使用してください。


参考リポジトリと Gist

出典

コメント