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"
}