通过查看Lighting.hlsl,可以看到GetMainLight
方法,其中有一个方法是通过阴影坐标来获取不前的阴影值。具体操作是在顶点计算中获取当前顶点的世界坐标,然后在片断着色中通过世界坐标来获取阴影坐标,然后再获取阴影值。如下面的代码片断:
v2f vert (appdata v)
{
v2f o;
o.vertex = TransformObjectToHClip(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.W = TransformObjectToWorld(v.vertex.xyz);//获取世界坐标
o.N = TransformObjectToWorldNormal(v.normal);
return o;
}
half4 frag (v2f i) : SV_Target
{
float3 N = normalize(i.N);
Light l = GetMainLight(TransformWorldToShadowCoord(i.W)); //获取当前的光照信息,包含阴影值
float3 L = normalize(l.direction);
// sample the texture
half4 col = _MainTex.Sample(sampler_MainTex, i.uv);
half lambert = dot(N,L) * 0.5 + 0.5;
lambert *= l.shadowAttenuation; //获取阴影值
half col2 = smoothstep(_Step-0.0001,_Step,lambert)*_Ramp+(1.0-_Ramp);
return col2 * col * _Color;
}
还需要一个LightMode="ShadowCaster"的Pass
,用于计算阴影,这个Pass的代码可以在URP的源码中看到,直接抄过来就行了,唯一需要注意的是GetShadowPositionHClips
这个方法最后有一个s
,其次还需要在上面的CBUFFER中的值也要写到这个ShadowCaster的pass中,这样才支持SRP Batch。
下面是完整shadow
Shader "URP/Ramp"
{
Properties
{
_Color("Color",Color) = (1,1,1,1)
_MainTex ("Texture", 2D) = "white" {}
_Ramp("Ramp",Range(0,1)) = 0.1 //控制亮暗值的对比
_Step("Step",Range(0,1)) = 0.5 //光照亮度在哪个值时区分显示
}
SubShader
{
Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalRenderPipeline" "LightMode" = "UniversalForward" }
LOD 100
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
// Universal Pipeline keywords
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
#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)
float4 _MainTex_ST;
half _Ramp;
real4 _Color;
real _Step;
CBUFFER_END
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float3 N : NORMAL;
float3 W : TEXCOORD1;
float4 vertex : SV_POSITION;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
v2f vert (appdata v)
{
v2f o;
o.vertex = TransformObjectToHClip(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.W = TransformObjectToWorld(v.vertex.xyz);
o.N = TransformObjectToWorldNormal(v.normal);
return o;
}
half4 frag (v2f i) : SV_Target
{
float3 N = normalize(i.N);
Light l = GetMainLight(TransformWorldToShadowCoord(i.W)); //GetMainLight();
float3 L = normalize(l.direction);
// sample the texture
half4 col = _MainTex.Sample(sampler_MainTex, i.uv);
half lambert = dot(N,L) * 0.5 + 0.5;
lambert *= l.shadowAttenuation;
half col2 = smoothstep(_Step-0.0001,_Step,lambert)*_Ramp+(1.0-_Ramp);
return col2 * col * _Color;
}
ENDHLSL
}
Pass
{
Tags { "LightMode" = "ShadowCaster" }
ZWrite On
ZTest LEqual
HLSLPROGRAM
#pragma vertex ShadowPassVertex
#pragma fragment ShadowPassFragment
// GPU Instancing
#pragma multi_compile_instancing
#include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
float3 _LightDirection;
//和上一个pass一样,用于支持SRP Batch
CBUFFER_START(UnityPerMaterial)
float4 _MainTex_ST;
half _Ramp;
real4 _Color;
real _Step;
CBUFFER_END
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float2 uv : TEXCOORD0;
float4 positionCS : SV_POSITION;
};
// 获取裁剪空间下的阴影坐标
float4 GetShadowPositionHClips(Attributes input)
{
float3 positionWS = TransformObjectToWorld(input.positionOS.xyz);
float3 normalWS = TransformObjectToWorldNormal(input.normalOS);
float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, _LightDirection));
#if UNITY_REVERSED_Z
positionCS.z = min(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE);
#else
positionCS.z = max(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE);
#endif
return positionCS;
}
Varyings ShadowPassVertex(Attributes input)
{
Varyings output;
UNITY_SETUP_INSTANCE_ID(input);
output.uv = TRANSFORM_TEX(input.texcoord, _MainTex);
output.positionCS = GetShadowPositionHClips(input);
return output;
}
half4 ShadowPassFragment(Varyings input): SV_TARGET
{
Alpha(SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a, _BaseColor, _Cutoff);
return 0;
}
ENDHLSL
}
}
}
效果图