2023/09/19 : 初稿
2023/12/14 : 追記
2024/08/20 : シーンの影の色(_SubtractiveShadowColor)を適用。さらにおまけで単純なLitシェーダーを書いてみた
Unity : 2021.3.29f1
URP : 12.1.12
マシン : M1Mac(Metal)
追記
エディタでは問題ないのにビルドするとピンク。なんでだと思ったら・・
間違い : "RenderPipeline"="UniversalRenderPipeline"
正解 : "RenderPipeline"="UniversalPipeline"
え、元からそうだっけ?Unity2022辺りから変わった?
本編
Unity税を考えるとUEへの移行をすべきかもしれない、
というのは置いておきまして。
UnityCG.cgincを使った記事はちらほら見かけるのですが、
URP12以降に対応したのが見つからなかったので書いときます。
こんな感じ?
Shader "Utils/ShadowOnlyGround"
{
Properties
{
_ShadowAlpha("ShadowAlpha", float) = 1
}
SubShader
{
Tags {
"RenderType"="Opaque"
"RenderPipeline"="UniversalPipeline" // Unity2021では "RenderPipeline"="UniversalRenderPipeline" だったような
"Queue"="Geometry+1"
}
Pass
{
Tags { "LightMode"="UniversalForward" }
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
// -------------------------------------
// Universal Render Pipeline keywords
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
#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"
CBUFFER_START(UnityPerMaterial)
float _ShadowAlpha;
CBUFFER_END
struct appdata
{
float4 vertex : POSITION;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 posWS : TEXCOORD0;
float fogFactor: TEXCOORD1;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = TransformObjectToHClip(v.vertex.xyz);
o.posWS = TransformObjectToWorld(v.vertex.xyz);
o.fogFactor = ComputeFogFactor(o.vertex.z);
return o;
}
half4 frag(v2f i) : SV_Target
{
float4 shadowCoord = TransformWorldToShadowCoord(i.posWS);
Light mainLight = GetMainLight(shadowCoord);
half shadow = mainLight.shadowAttenuation;
float4 col = float4(_SubtractiveShadowColor.xyz, (1 - shadow) * _ShadowAlpha);
col.rgb = MixFog(col.rgb, i.fogFactor);
return col;
}
ENDHLSL
}
// Used for rendering shadowmaps
UsePass "Universal Render Pipeline/Lit/ShadowCaster"
}
}
おまけ
単純なLitシェーダーを自作してみる実験。Unlitはよくネットに転がってますがLitってなかなかないんですよね。自作するときの足がかりにどうぞ。なお、アンビエントとかはUnity標準のシェーダーとは違いますし、GI、ノーマルマップやエミッションやらは追加してないのでセルフでお願いします。
なお、このままだと_CameraDepthTextureに書き込まれません。_CameraDepthTextureに書き込むためには、DepthNormalsOnlyパスを追加する必要があります。なぜDepthOnlyではないのか謎。
Shader "ProjectMain/Lit"
{
Properties
{
// ベースカラー
[MainTexture] _BaseMap("Texture", 2D) = "white" {}
[MainColor] _BaseColor("Color", Color) = (1, 1, 1, 1)
// アンビエント
_AmbientColor("Ambient", Color) = (0.1, 0.1, 0.1, 0.1)
// Photoshopのオーバーレイ
_EnableOverlay("EnableOverlay", Float) = 0
_OverlayTex("OverlayTex", 2D) = "black" {}
}
SubShader
{
Tags {
"RenderType" = "Opaque"
"RenderPipeline" = "UniversalPipeline"
"Queue"="Geometry"
}
Pass
{
Tags { "LightMode" = "UniversalForward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
// 影用
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
#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"
//#include "Assets/ProjectMain/Shaders/SkyboxFunctions.hlsl"
// BaseMap sampler
TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);
// Photoshopのオーバーレイ用sampler
TEXTURE2D(_OverlayTex);
SAMPLER(sampler_OverlayTex);
// for SRP Batcher
CBUFFER_START(UnityPerMaterial)
// BaseMap
float4 _BaseMap_ST;
half4 _BaseColor;
// アンビエント
half4 _AmbientColor;
// Photoshopのオーバーレイ用
half _EnableOverlay;
float4 _OverlayTex_ST;
CBUFFER_END
// 頂点入力
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float4 tangentOS : TANGENT;
float2 uv : TEXCOORD0;
};
// 頂点出力
struct Varyings
{
float2 uv : TEXCOORD0;
float3 positionWS : TEXCOORD1;
float3 normalWS : TEXCOORD2;
float2 fogCoord : TEXCOORD3;
float4 positionCS : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO
};
// 頂点
Varyings vert(Attributes input)
{
Varyings output = (Varyings)0;
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
output.positionCS = vertexInput.positionCS;
output.positionWS = vertexInput.positionWS;
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
output.fogCoord = float2(ComputeFogFactor(vertexInput.positionCS.z), vertexInput.positionVS.z);
VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS);
output.normalWS = normalInput.normalWS;
return output;
}
// フラグメント
half4 frag(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
float4 shadowCoords = TransformWorldToShadowCoord(input.positionWS);
// Diffuseカラー
half2 uv = input.uv;
float4 texColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv);
// Photoshopのオーバーレイ
if (_EnableOverlay > 0.5) {
#if !UNITY_COLORSPACE_GAMMA
texColor.rgb = LinearToSRGB(texColor.rgb);
float4 overlayTex = SAMPLE_TEXTURE2D(_OverlayTex, sampler_OverlayTex, uv);
overlayTex.rgb = LinearToSRGB(overlayTex.rgb);
#endif
texColor.rgb = texColor.rgb < 0.5 ? 2.0 * texColor.rgb * overlayTex.rgb : 1.0 - 2.0 * (1.0 - texColor.rgb) * (1.0 - overlayTex.rgb);
#if !UNITY_COLORSPACE_GAMMA
texColor.rgb = SRGBToLinear(texColor.rgb);
#endif
}
// RGBA確定
half3 baseColor = texColor.rgb * _BaseColor.rgb;
half alpha = texColor.a * _BaseColor.a;
// メイン方向光源
Light mainLight = GetMainLight(shadowCoords);
float NoL = dot(input.normalWS, mainLight.direction);
float3 color = baseColor * mainLight.color * mainLight.distanceAttenuation * NoL;
// 追加光源
uint pixelLightCount = GetAdditionalLightsCount();
for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex) {
Light light = GetAdditionalLight(lightIndex, input.positionWS);
half add_NoL = saturate(dot(input.normalWS, light.direction));
color += baseColor * light.color * light.distanceAttenuation * add_NoL;
}
// 影
half shadowAmount = MainLightRealtimeShadow(shadowCoords);
color.xyz = lerp(color.xyz, _SubtractiveShadowColor.xyz, 1 - shadowAmount);
// アンビエント
color = max(color, _AmbientColor.rgb);
// フォグ
color = MixFog(color, input.fogCoord.x);
// 空に溶ける
//float4 skyboxColor = CalcSkyboxColor(input.positionWS);
//float viewZ = abs(input.fogCoord.y);
//float viewZ01 = viewZ * _ProjectionParams.w;
//color.rgb = lerp(color.rgb, skyboxColor.rgb, viewZ01);
// 結果
return half4(color, alpha);
}
ENDHLSL
}
// Used for rendering shadowmaps
UsePass "Universal Render Pipeline/Lit/ShadowCaster"
}
FallBack "Hidden/Universal Render Pipeline/FallbackError"
}