Hi all,
I’ve been trying to create a toon shader for our game recently in URP 2022.1.15f1, however, I’ve been running into issues with shadow acne when it comes to the shadow attenuation as well as sampling the shadow mask.
I’ve recreated a basic setup for a toon shader that still has the problem. The trouble is, when I multiply the results by the shadow & distance attenuation there is really bad shadow acne occuring, however, when I don’t do this the shader no longer receives shadows.
Shadow acne when multiplied with shadow/distance attentuation
If I plug the shadow attenuation into the base colour you can see what is getting remapped to the texture gradient.
Shadow attentuation plugged directly into base colour
When I multiply by the sampled shadow mask instead of the shadow/distance attenuation I still get similar results.
Graph using shadow mask instead of attenuation
While it looks like this fixes it this actually doesn’t as this only works when the ramp is split down the middle at a value of 0.5.
If I change it to a smooth gradient for example you can see that the issue is still there, though it is improved slightly. I use a different ramp for different objects if I use a smooth gradient to as seem below to clearly show the issue or a gradient texture with multiple shading bandings it’s very clear the issue. I can adjust it slightly using the URP asset shadow settings as well as the depth/normal bias settings but this doesn’t fix the issue.
Shadow issues when using smooth gradient
This also occurs on additional light shadows as well.
Shadow acne from additional lights
This is the stripped down code used in the graph example above.
HLSL lighting code
#ifndef CUSTOM_LIGHTING_DEMO_INCLUDED
#define CUSTOM_LIGHTING_DEMO_INCLUDED
#ifdef UNIVERSAL_LIGHTING_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RealtimeLights.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#endif
void MainLight_float (float3 WorldPos, out float3 Direction, out float3 Color, out float DistanceAtten, out float ShadowAtten){
#ifdef SHADERGRAPH_PREVIEW
Direction = float3(0.5, 0.5, 0);
Color = 1;
DistanceAtten = 1;
ShadowAtten = 1;
#else
#if SHADOWS_SCREEN
half4 clipPos = TransformWorldToHClip(WorldPos);
half4 shadowCoord = ComputeScreenPos(clipPos);
#else
half4 shadowCoord = TransformWorldToShadowCoord(WorldPos);
#endif
Light mainLight = GetMainLight(shadowCoord);
Direction = mainLight.direction;
Color = mainLight.color;
DistanceAtten = mainLight.distanceAttenuation;
//hadowAtten = mainLight.shadowAttenuation;
#if !defined(_MAIN_LIGHT_SHADOWS) || defined(_RECEIVE_SHADOWS_OFF)
ShadowAtten = 1.0f;
#endif
#if SHADOWS_SCREEN
ShadowAtten = SampleScreenSpaceShadowmap(shadowCoord);
#else
ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData();
float shadowStrength = GetMainLightShadowStrength();
ShadowAtten = SampleShadowmap(shadowCoord, TEXTURE2D_ARGS(_MainLightShadowmapTexture,
sampler_MainLightShadowmapTexture),
shadowSamplingData, shadowStrength, false);
#endif
#endif
}
void Shadowmask_half (float2 lightmapUV, out half4 Shadowmask){
#ifdef SHADERGRAPH_PREVIEW
Shadowmask = half4(1,1,1,1);
#else
OUTPUT_LIGHTMAP_UV(lightmapUV, unity_LightmapST, lightmapUV);
Shadowmask = SAMPLE_SHADOWMASK(lightmapUV);
#endif
}
#ifndef SHADERGRAPH_PREVIEW
#include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"
#if (SHADERPASS != SHADERPASS_FORWARD)
#undef REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR
#endif
#endif
void MainLightShadows_float (float3 WorldPos, half4 Shadowmask, out float ShadowAtten){
#ifdef SHADERGRAPH_PREVIEW
ShadowAtten = 1;
#else
float4 shadowCoord = TransformWorldToShadowCoord(WorldPos);
ShadowAtten = MainLightShadow(shadowCoord, WorldPos, Shadowmask, _MainLightOcclusionProbes);
#endif
}
#endif
Any help is greatly appreciated! I’m sure I must be missing something but I’ve search everywhere online and can’t find a solution anywhere.