2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HDRP環境で使用できるMtoonみたいなshader

Last updated at Posted at 2025-01-05

HDRP環境で使用できるMtoonみたいなshader
未完成なのでいい案ください

Shader "Custom/HDRPMToon2024"
{
    Properties
    {
        // Render Settings
        // Render Settings
        [Header(Rendering)]
        [Enum(Opaque,0,Cutout,1,Transparent,2,TransparentWithZWrite,3)] _RenderMode("Rendering Type", Float) = 0
        [Space]
        [Enum(UnityEngine.Rendering.CullMode)] _CullMode("Cull Mode", Float) = 2
        [HideInInspector] _SrcBlend("Source Blend", Float) = 1
        [HideInInspector] _DstBlend("Destination Blend", Float) = 0
        [HideInInspector] _ZWrite("ZWrite", Float) = 1.0
        [HideInInspector] _AlphaSrcBlend("Source Blend Alpha", Float) = 1
        [HideInInspector] _AlphaDstBlend("Destination Blend Alpha", Float) = 0
        [HideInInspector][ToggleUI] _TransparentZWrite("Transparent ZWrite", Float) = 0
        [HideInInspector] _ZTestDepthEqualForOpaque("ZTest Depth Equal For Opaque", Int) = 4
        [HideInInspector][ToggleUI] _TransparentBackfaceEnable("Transparent Backface Enable", Float) = 0
        
        // Main
        [MainTexture] _BaseMap("Lit Color, Alpha", 2D) = "white" {}
        [MainColor] _BaseColor("Lit Color, Alpha", Color) = (1,1,1,1)
        
        // Lighting
        _ShadeColor("Shade Color", Color) = (0.97, 0.81, 0.86, 1)
        [NoScaleOffset] _ShadeMap("Shade Map", 2D) = "white" {}
        _ShadeToony("Shade Toony", Range(0, 1)) = 0.9
        _ShadingShiftFactor("Shading Shift", Range(-1, 1)) = 0
        _ShadingToonyFactor("Shading Toony", Range(0, 1)) = 0.95
        _ShadingGradeRate("Shading Grade Rate", Range(0, 1)) = 1
        _ShadeShift("Shade Shift", Range(-1, 1)) = 0
        
        // Normal
        [Normal] _BumpMap("Normal Map", 2D) = "bump" {}
        _BumpScale("Normal Scale", Float) = 1.0
                
        // MatCap
        [NoScaleOffset] _MatCapTex("MatCap", 2D) = "black" {}
        [HDR]_MatCapColor("MatCap Color", Color) = (1,1,1,1) // HDRカラーとして定義
        
        // Rim Light
        [HDR]_RimColor("Rim Color", Color) = (1,1,1,1)
        _RimLightingMix("Rim Lighting Mix", Range(0, 1)) = 0.0
        _RimFresnelPower("Rim Fresnel Power", Range(0, 100)) = 5.0
        _RimLift("Rim Lift", Range(0, 1)) = 0.0
        _RimDirectionLightContribution("Rim Direction Light Contribution", Range(0, 1)) = 1.0
        _RimLightMode("Rim Light Mode", Float) = 0
        _RimBlendStart("Rim Blend Start", Range(0, 1)) = 0
        _RimBlendEnd("Rim Blend End", Range(0, 1)) = 1
        
        // Emission
        [HDR]_EmissionColor("Emission Color", Color) = (0,0,0,1)
        [NoScaleOffset]_EmissionMap("Emission Map", 2D) = "white" {}
        
        // Outline
        _OutlineWidth("Outline Width", Range(0, 0.1)) = 0.001
        _OutlineColor("Outline Color", Color) = (0,0,0,1)
        [Enum(None,0,WorldCoordinates,1,ScreenCoordinates,2)] _OutlineWidthMode("Outline Width Mode", Float) = 0
        _OutlineScaledMaxDistance("Outline Scaled Max Distance", Float) = 1
        _OutlineLightingMix("Outline Lighting Mix", Range(0, 1)) = 1
        _OutlineWidthColorMode("Outline Width Color Mode", Float) = 0
        _OutlineColorMode("Outline Color Mode", Float) = 0
        _OutlineColorFactor("Outline Color Factor", Range(0, 1)) = 1
        _OutlineLightingMixFactor("Outline Lighting Mix Factor", Range(0, 1)) = 1
        
        // UV Animation
        _UvAnimMaskTexture("UV Animation Mask", 2D) = "white" {}
        _UvAnimScrollX("UV Animation Scroll X", Float) = 0
        _UvAnimScrollY("UV Animation Scroll Y", Float) = 0
        _UvAnimRotation("UV Animation Rotation", Float) = 0
        
        // Advanced
        _IndirectLightIntensity("Indirect Light Intensity", Range(0, 1)) = 0.1
        _GiEqualization("GI Equalization", Range(0, 1)) = 0.9
        _LightColorAttenuation("Light Color Attenuation", Range(0, 1)) = 0
        [HDR]_SkyColor("Sky Color", Color) = (0.5, 0.5, 0.5, 1)
        [HDR]_GroundColor("Ground Color", Color) = (0.2, 0.2, 0.2, 1)
        
        // Alpha
        _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
        [Toggle] _AlphaCutoutEnable("Alpha Cutout Enable", Float) = 0
        [Toggle] _TransparentEnable("Transparent Enable", Float) = 0

        [HideInInspector] _Surface("__surface", Float) = 0.0
        [HideInInspector] _BlendMode("__blend", Float) = 0.0
        [HideInInspector] _AlphaCutoffEnable("__AlphaCutoffEnable", Float) = 0.0
    }

    SubShader
    {
        Tags
        { 
            "RenderPipeline" = "HDRenderPipeline" 
            "RenderType" = "Transparent"
            "Queue" = "Transparent"
        }

        HLSLINCLUDE
        #pragma target 4.5
                
        // キーワードの整理
        #pragma shader_feature_local_fragment _MATCAP_ON
        #pragma multi_compile _ _ALPHATEST_ON
        #pragma multi_compile _ _ALPHABLEND_ON
        #pragma multi_compile _ _OPAQUE_MODE
        #pragma multi_compile _ _ZWRITE_ON

        #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
        #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
        #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl"
        #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl"
        
        TEXTURE2D(_BaseMap);
        SAMPLER(sampler_BaseMap);
        TEXTURE2D(_ShadeMap);
        SAMPLER(sampler_ShadeMap);
        TEXTURE2D(_BumpMap);
        SAMPLER(sampler_BumpMap);
        TEXTURE2D(_MatCapTex);
        SAMPLER(sampler_MatCapTex);
        TEXTURE2D(_EmissionMap);
        SAMPLER(sampler_EmissionMap);
        TEXTURE2D(_UvAnimMaskTexture);
        SAMPLER(sampler_UvAnimMaskTexture);

        CBUFFER_START(UnityPerMaterial)
            // 既存のバッファー定義に加えて新しいプロパティを追加
            float4 _BaseMap_ST;
            float4 _BaseColor;
            float4 _ShadeColor;
            float _ShadeToony;
            float _ShadingShiftFactor;
            float _ShadingToonyFactor;
            float _ShadingGradeRate;
            float _ShadeShift;
            float _BumpScale;
            float4 _MatCapColor;
            float4 _RimColor;
            float _RimLightingMix;
            float _RimFresnelPower;
            float _RimLift;
            float _RimDirectionLightContribution;
            float _RimLightMode;
            float _RimBlendStart;
            float _RimBlendEnd;
            float4 _EmissionColor;
            float _IndirectLightIntensity;
            float _GiEqualization;
            float _LightColorAttenuation;
            float _Cutoff;
            float _OutlineWidth;
            float4 _OutlineColor;
            float _OutlineWidthMode;
            float _OutlineScaledMaxDistance;
            float _OutlineLightingMix;
            float _OutlineWidthColorMode;
            float _OutlineColorMode;
            float _OutlineColorFactor;
            float _OutlineLightingMixFactor;
            float _UvAnimScrollX;
            float _UvAnimScrollY;
            float _UvAnimRotation;
            float4 _SkyColor;
            float4 _GroundColor;
            float _AlphaCutoutEnable;
            float _TransparentEnable;
            float _ZWrite;
            float _Surface;
            float _BlendMode;
            float _AlphaCutoffEnable;
        CBUFFER_END

        // 既存の構造体定義
        struct AppData
        {
            float4 positionOS : POSITION;
            float3 normalOS : NORMAL;
            float4 tangentOS : TANGENT;
            float2 texcoord : TEXCOORD0;
            UNITY_VERTEX_INPUT_INSTANCE_ID
        };

        struct Varyings
        {
            float4 positionCS : SV_POSITION;
            float2 uv : TEXCOORD0;
            float3 positionWS : TEXCOORD1;
            float3 normalWS : TEXCOORD2;
            float4 tangentWS : TEXCOORD3;
            float3 viewDirWS : TEXCOORD4;
            UNITY_VERTEX_INPUT_INSTANCE_ID
        };

        float2 RotateUV(float2 uv, float rotation)
        {
            float cos_rot = cos(rotation);
            float sin_rot = sin(rotation);
            float2 piv = float2(0.5, 0.5);
            float2 uv_rot = uv - piv;
            float2 rotated = float2(
                cos_rot * uv_rot.x - sin_rot * uv_rot.y,
                sin_rot * uv_rot.x + cos_rot * uv_rot.y
            );
            return rotated + piv;
        }

        float2 GetAnimatedUV(float2 uv)
        {
            float2 scrolledUV = uv + float2(_UvAnimScrollX, _UvAnimScrollY) * _Time.y;
            return RotateUV(scrolledUV, _UvAnimRotation * _Time.y);
        }

        float3 GetAmbientLight(float3 positionWS, float3 normalWS)
        {
            float3 ambient = float3(0.0, 0.0, 0.0);
            float weight = 0.0f;
            float3 upperHemisphereColor = _SkyColor.rgb;
            float3 lowerHemisphereColor = _GroundColor.rgb;
            float upDot = dot(normalWS, float3(0.0, 1.0, 0.0));
            ambient = lerp(lowerHemisphereColor, upperHemisphereColor, upDot * 0.5 + 0.5);
            return ambient * _GiEqualization;
        }

        float3 CalculateToonDiffuse(float3 normal, float3 lightDir, float shadingGradeRate)
        {
            float ndotl = dot(normal, normalize(lightDir));
            float shadeShift = _ShadeShift + _ShadingShiftFactor;
            float shadingGrade = 1.0 - _ShadeToony * shadingGradeRate;
            float lighting = saturate((ndotl + shadeShift) / (1.0 + shadeShift));
            return float3(smoothstep(shadingGrade, 1.0, lighting), 
                         smoothstep(shadingGrade, 1.0, lighting),
                         smoothstep(shadingGrade, 1.0, lighting));
        }

        // Modified rim lighting calculation
        float3 CalculateRimLighting(float3 normal, float3 viewDir, float3 lightDir)
        {
            float rim = 1.0 - saturate(dot(viewDir, normal));
            float rimBlend = smoothstep(_RimBlendStart, _RimBlendEnd, rim);
            rim = pow(rim, _RimFresnelPower);
            rim = smoothstep(_RimLift, 1.0, rim);
            
            float lightContribution = 1.0;
            if (_RimLightMode == 1)
            {
                float ndotl = dot(normal, lightDir);
                lightContribution = smoothstep(0.0, 0.5, ndotl);
            }
            
            return _RimColor.rgb * rim * _RimLightingMix * lightContribution;
        }

        float3 CalculateOutlineVertexPosition(float4 positionOS, float3 normalOS, float outlineWidth, float outlineWidthMode)
        {
            float3 positionWS = TransformObjectToWorld(positionOS.xyz);
            float3 normalWS = TransformObjectToWorldNormal(normalOS);
            
            float outlineScale = 1;
            if (outlineWidthMode == 1) // WorldCoordinates
            {
                outlineScale = 1;
            }
            else if (outlineWidthMode == 2) // ScreenCoordinates
            {
                float4 projectedNormal = normalize(mul(UNITY_MATRIX_P, float4(normalWS, 0)));
                float4 projectedPosition = mul(UNITY_MATRIX_P, float4(positionWS, 1));
                float distanceScale = min(_OutlineScaledMaxDistance, distance(_WorldSpaceCameraPos, positionWS));
                outlineScale = distanceScale * length(projectedNormal.xy);
            }
            
            return positionOS.xyz + normalOS * outlineWidth * outlineScale;
        }

        ENDHLSL

        // Opaque Pass
        Pass
        {
            Name "ForwardOnly"
            Tags { "LightMode" = "ForwardOnly" }

            Blend [_SrcBlend] [_DstBlend]
            ZWrite [_ZWrite]
            Cull [_CullMode]

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            Varyings vert(AppData input)
            {
                Varyings output = (Varyings)0;
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_TRANSFER_INSTANCE_ID(input, output);

                float2 uv = GetAnimatedUV(input.texcoord);
                output.uv = TRANSFORM_TEX(uv, _BaseMap);

                output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
                output.positionWS = TransformObjectToWorld(input.positionOS.xyz);
                output.normalWS = TransformObjectToWorldNormal(input.normalOS);
                output.tangentWS = float4(TransformObjectToWorldDir(input.tangentOS.xyz), input.tangentOS.w);
                output.viewDirWS = normalize(GetWorldSpaceViewDir(output.positionWS));

                return output;
            }

            float4 frag(Varyings input) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID(input);

                float4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
                float4 baseColor = baseMap * _BaseColor;
                
                #ifdef _ALPHATEST_ON
                    clip(baseColor.a - _Cutoff);
                #endif

                float4 shadeMap = SAMPLE_TEXTURE2D(_ShadeMap, sampler_ShadeMap, input.uv);
                
                float3 normalTS = UnpackNormalScale(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, input.uv), _BumpScale);
                float3 bitangent = normalize(cross(input.normalWS, input.tangentWS.xyz)) * input.tangentWS.w;
                float3x3 tangentToWorld = float3x3(normalize(input.tangentWS.xyz), bitangent, input.normalWS);
                float3 normalWS = normalize(mul(normalTS, tangentToWorld));

                float3 lightDir = float3(0.5, 0.5, -0.5);
                float3 lightColor = float3(1.0, 1.0, 1.0);
                float shadingGrade = SAMPLE_TEXTURE2D(_UvAnimMaskTexture, sampler_UvAnimMaskTexture, input.uv).r * _ShadingGradeRate;
                
                float3 toonDiffuse = CalculateToonDiffuse(normalWS, lightDir, shadingGrade);
                float lighting = toonDiffuse.r; // All components are the same
                
                float3 finalColor = lerp(shadeMap.rgb * _ShadeColor.rgb, baseColor.rgb, lighting);
                finalColor = lerp(finalColor, finalColor * lightColor, _LightColorAttenuation);

                #ifdef _MATCAP_ON
                    // 視線方向での法線の計算を修正
                    float3 viewNormal = normalize(mul(UNITY_MATRIX_IT_MV, float4(normalWS, 0.0)).xyz);
                    float2 matcapUV = viewNormal.xy * 0.5 + 0.5;
                    float3 matCap = SAMPLE_TEXTURE2D(_MatCapTex, sampler_MatCapTex, matcapUV).rgb;
                    
                    // マットキャップの合成方法を加算合成に変更
                    float3 matCapColor = matCap.rgb * _MatCapColor.rgb;
                    finalColor += matCapColor * _MatCapColor.a;
                #endif

                float3 rimColor = CalculateRimLighting(normalWS, input.viewDirWS, lightDir);
                finalColor += rimColor;
                
                float3 emission = SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, input.uv).rgb * _EmissionColor.rgb;
                finalColor += emission;

                float3 ambient = GetAmbientLight(input.positionWS, normalWS);
                float3 indirectLight = ambient * _IndirectLightIntensity;
                finalColor += indirectLight * baseColor.rgb;

                return float4(finalColor, baseColor.a);
            }
            ENDHLSL
        }

        // Outline Pass
        Pass
        {
            Name "Outline"
            Tags { "LightMode" = "ForwardOnly" }
            
            Cull Front
            
            HLSLPROGRAM
            #pragma vertex outlineVert
            #pragma fragment outlineFrag

            Varyings outlineVert(AppData input)
            {
                Varyings output = (Varyings)0;
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_TRANSFER_INSTANCE_ID(input, output);

                float3 posOS = CalculateOutlineVertexPosition(input.positionOS, input.normalOS, _OutlineWidth, _OutlineWidthMode);
                
                output.positionCS = TransformObjectToHClip(posOS);
                output.positionWS = TransformObjectToWorld(posOS);
                output.normalWS = TransformObjectToWorldNormal(input.normalOS);
                output.tangentWS = float4(TransformObjectToWorldDir(input.tangentOS.xyz), input.tangentOS.w);
                output.viewDirWS = normalize(GetWorldSpaceViewDir(output.positionWS));
                output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);

                return output;
            }

            float4 outlineFrag(Varyings input) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID(input);
                
                float4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
                float4 outlineColor = _OutlineColor;
                
                if (_OutlineColorMode == 1) // Multiply with texture
                {
                    outlineColor *= baseMap;
                }
                
                float3 lightDir = float3(0.5, 0.5, -0.5);
                float lighting = dot(input.normalWS, normalize(lightDir)) * 0.5 + 0.5;
                outlineColor.rgb = lerp(outlineColor.rgb, outlineColor.rgb * lighting, _OutlineLightingMixFactor);
                
                return outlineColor;
            }
            ENDHLSL
        }

        // GBuffer Pass
        Pass
        {
            Name "GBuffer"
            Tags { "LightMode" = "GBuffer" }

            HLSLPROGRAM
            #pragma vertex Vert
            #pragma fragment Frag
            
            #define SHADERPASS SHADERPASS_GBUFFER
            
            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
            #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
            #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl"
            #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/FragInputs.hlsl"

            struct AttributesMesh
            {
                float3 positionOS   : POSITION;
                float3 normalOS     : NORMAL;
                float4 tangentOS    : TANGENT;
                float2 texCoord0    : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct PackedVaryingsmeshToPS
            {
                float4 positionCS   : SV_Position;
                float3 positionWS   : TEXCOORD0;
                float3 normalWS     : TEXCOORD1;
                float4 tangentWS    : TEXCOORD2;
                float2 texCoord0    : TEXCOORD3;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            PackedVaryingsmeshToPS Vert(AttributesMesh inputMesh)
            {
                PackedVaryingsmeshToPS output;
                UNITY_SETUP_INSTANCE_ID(inputMesh);
                UNITY_TRANSFER_INSTANCE_ID(inputMesh, output);

                float3 positionWS = TransformObjectToWorld(inputMesh.positionOS);
                output.positionCS = TransformWorldToHClip(positionWS);
                output.positionWS = positionWS;
                output.normalWS = TransformObjectToWorldNormal(inputMesh.normalOS);
                output.tangentWS = float4(TransformObjectToWorldDir(inputMesh.tangentOS.xyz), inputMesh.tangentOS.w);
                output.texCoord0 = inputMesh.texCoord0;

                return output;
            }

        // GBuffer Passの改善提案
        void Frag(PackedVaryingsmeshToPS packedInput,
            out float4 outGBuffer0 : SV_Target0,
            out float4 outGBuffer1 : SV_Target1,
            out float4 outGBuffer2 : SV_Target2,
            out float4 outGBuffer3 : SV_Target3)
        {
            UNITY_SETUP_INSTANCE_ID(packedInput);

            float2 uv = packedInput.texCoord0;
            float4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv);
            float4 baseColor = baseMap * _BaseColor;
            float4 shadeMap = SAMPLE_TEXTURE2D(_ShadeMap, sampler_ShadeMap, uv);

            #ifdef _ALPHATEST_ON
                clip(baseColor.a - _Cutoff);
            #endif

            // 法線計算の改善
            float3 normalTS = UnpackNormalScale(SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, uv), _BumpScale);
            float3 bitangent = normalize(cross(packedInput.normalWS, packedInput.tangentWS.xyz)) * packedInput.tangentWS.w;
            float3x3 tangentToWorld = float3x3(normalize(packedInput.tangentWS.xyz), bitangent, packedInput.normalWS);
            float3 normalWS = normalize(mul(normalTS, tangentToWorld));

            // シェーディンググレードの計算
            float shadingGrade = SAMPLE_TEXTURE2D(_UvAnimMaskTexture, sampler_UvAnimMaskTexture, uv).r * _ShadingGradeRate;
            float shadeShift = _ShadeShift + _ShadingShiftFactor;
            float shadingToony = lerp(1.0, _ShadingToonyFactor, shadingGrade);

            // エミッション
            float3 emissiveColor = SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, uv).rgb * _EmissionColor.rgb;

            // MatCapの処理
            #ifdef _MATCAP_ON
                float3 viewNormal = mul((float3x3)UNITY_MATRIX_V, normalWS);
                float2 matcapUV = viewNormal.xy * 0.5 + 0.5;
                float3 matCapColor = SAMPLE_TEXTURE2D(_MatCapTex, sampler_MatCapTex, matcapUV).rgb * _MatCapColor.rgb;
            #else
                float3 matCapColor = 0;
            #endif

            // GBufferへの改善された出力
            outGBuffer0 = float4(baseColor.rgb, baseColor.a);                    // Albedo + Alpha
            outGBuffer1 = float4(shadeMap.rgb * _ShadeColor.rgb, shadingToony); // Shade Color + Toony
            outGBuffer2 = float4(normalWS * 0.5 + 0.5, _ShadingGradeRate);      // Normal + Shading Grade
            outGBuffer3 = float4(emissiveColor + matCapColor,                    // Emission + MatCap
                                shadeShift);                                     // Shade Shift
        }
            ENDHLSL
        }
    }
    CustomEditor "MToon.HDRPMToonInspector"
}
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?