Refactor shadowcaster to use explicit plane basis

Replaces the use of world-to-local matrices for shadowcaster planes with explicit plane origin, basis, and normal vectors in both C# and shader code. Updates property setting in ShadowcasterUpdater and its editor preview, and rewrites the shadow sampling function in the shader include to use the new basis. Adjusts all affected shaders to use the new properties and sampling function for improved clarity and flexibility.
This commit is contained in:
DeMuenu
2025-10-01 13:26:33 +02:00
parent 841d99ad0e
commit 0e633983cf
5 changed files with 225 additions and 191 deletions

View File

@@ -1,141 +1,151 @@
#if UNITY_EDITOR #if UNITY_EDITOR
using System.Collections.Generic;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using System.Collections.Generic;
[InitializeOnLoad] [InitializeOnLoad]
public static class ShadowcasterUpdaterPreview public static class ShadowcasterUpdaterEditorLoop
{ {
const double kTickInterval = 0.1; // seconds private const double Interval = 0.1;
static double _nextTick; private const float Eps = 1e-6f;
// One shared MPB to avoid allocations each frame private static double _lastUpdateTime;
static readonly MaterialPropertyBlock sMPB = new MaterialPropertyBlock(); private static ShadowcasterUpdater[] _cached;
private static readonly MaterialPropertyBlock _mpb = new MaterialPropertyBlock();
// Cache: component -> property ID, and renderer -> last applied matrix static ShadowcasterUpdaterEditorLoop()
static readonly Dictionary<ShadowcasterUpdater, int> _propId = new Dictionary<ShadowcasterUpdater, int>();
static readonly Dictionary<Renderer, Matrix4x4> _lastW2L = new Dictionary<Renderer, Matrix4x4>();
static readonly List<Renderer> _toRemove = new List<Renderer>(32);
static ShadowcasterUpdaterPreview()
{ {
_lastUpdateTime = EditorApplication.timeSinceStartup;
EditorApplication.update += Update; EditorApplication.update += Update;
EditorApplication.hierarchyChanged += ForceTick; EditorApplication.hierarchyChanged += RefreshCache;
Undo.undoRedoPerformed += ForceTick; AssemblyReloadEvents.afterAssemblyReload += RefreshCache;
Selection.selectionChanged += ForceTick;
EditorApplication.playModeStateChanged += _ => ForceTick(); RefreshCache();
} }
public static void ForceTick() => _nextTick = 0; private static void RefreshCache()
static void Update()
{ {
#if UNITY_2019_1_OR_NEWER _cached = FindSceneUpdaters();
if (EditorApplication.isPlayingOrWillChangePlaymode) return; }
private static ShadowcasterUpdater[] FindSceneUpdaters()
{
#if UNITY_2020_1_OR_NEWER
return Object.FindObjectsOfType<ShadowcasterUpdater>(true);
#else #else
if (EditorApplication.isPlaying) return; // Unity 2019-compatible path: include inactive, filter out assets/prefabs not in a scene
#endif var all = Resources.FindObjectsOfTypeAll(typeof(ShadowcasterUpdater));
double now = EditorApplication.timeSinceStartup; var list = new List<ShadowcasterUpdater>(all.Length);
if (now < _nextTick) return; foreach (var o in all)
_nextTick = now + kTickInterval;
CleanupNullRenderers();
var behaviours = FindAllInScene();
foreach (var b in behaviours)
{ {
if (b == null || !b.isActiveAndEnabled) continue; var c = o as ShadowcasterUpdater;
if (EditorUtility.IsPersistent(b)) continue; // skip assets/prefabs if (c == null) continue;
ApplyToBehaviour(b); if (EditorUtility.IsPersistent(c)) continue; // skip assets
if (!c.gameObject.scene.IsValid()) continue;
list.Add(c);
}
return list.ToArray();
#endif
}
private static void Update()
{
if (EditorApplication.isPlayingOrWillChangePlaymode) return;
if (EditorApplication.isCompiling) return;
var now = EditorApplication.timeSinceStartup;
if (now - _lastUpdateTime < Interval) return;
_lastUpdateTime = now;
var arr = _cached;
if (arr == null || arr.Length == 0) return;
for (int i = 0; i < arr.Length; i++)
{
var u = arr[i];
if (u == null) continue;
TryUpdate(u);
} }
// Make changes visible in Scene/Game view without wiggling the mouse
SceneView.RepaintAll(); SceneView.RepaintAll();
} }
static ShadowcasterUpdater[] FindAllInScene() private static void TryUpdate(ShadowcasterUpdater u)
{ {
#if UNITY_2023_1_OR_NEWER // If inspector values changed, make sure textures/colors/min brightness are pushed
return Object.FindObjectsByType<ShadowcasterUpdater>(FindObjectsInactive.Exclude, FindObjectsSortMode.None); try
#elif UNITY_2020_1_OR_NEWER
return Object.FindObjectsOfType<ShadowcasterUpdater>(true);
#else
return Resources.FindObjectsOfTypeAll<ShadowcasterUpdater>();
#endif
}
static void CleanupNullRenderers()
{
_toRemove.Clear();
foreach (var kv in _lastW2L)
if (kv.Key == null) _toRemove.Add(kv.Key);
for (int i = 0; i < _toRemove.Count; i++)
_lastW2L.Remove(_toRemove[i]);
}
static int GetPropertyId(ShadowcasterUpdater b)
{
string name = string.IsNullOrEmpty(b.propertyName) ? "_Udon_WorldToLocal" : b.propertyName;
if (!_propId.TryGetValue(b, out int id))
{ {
id = Shader.PropertyToID(name); u.ApplyTextureData();
_propId[b] = id; }
return id; catch
{
// UdonSharp can be touchy during certain editor states. Ignore and continue.
} }
// If user changed the property name in inspector, refresh the ID var targets = u.rendererTargets;
int newId = Shader.PropertyToID(name); if (targets == null || targets.Length == 0) return;
if (newId != id)
// Match the runtime script's plane definition (0.5 half-size before scaling)
const float quadHalfWidth = 0.5f;
const float quadHalfHeight = 0.5f;
Transform t = u.transform;
// World-space basis from transform
Vector3 Udir = t.rotation * Vector3.right; // local +X
Vector3 Vdir = t.rotation * Vector3.up; // local +Y
// Half extents after non-uniform scaling
float halfW = Mathf.Max(quadHalfWidth * t.lossyScale.x, Eps);
float halfH = Mathf.Max(quadHalfHeight * t.lossyScale.y, Eps);
// Reciprocal axes so dot(r, Uinv/Vinv) -> [-0.5, 0.5]
Vector3 Uinv = Udir / (2.0f * halfW);
Vector3 Vinv = Vdir / (2.0f * halfH);
// Unit normal
Vector3 N = Vector3.Normalize(Vector3.Cross(Udir, Vdir));
int idx = Mathf.Max(0, u.shadowcasterIndex);
string suf = "_" + idx.ToString();
int idShadowTex = Shader.PropertyToID("_Udon_shadowCasterTex" + suf);
int idShadowColor = Shader.PropertyToID("_Udon_shadowCasterColor" + suf);
int idOutsideColor = Shader.PropertyToID("_Udon_OutSideColor" + suf);
int idMinBrightness = Shader.PropertyToID("_Udon_MinBrightnessShadow" + suf);
int idPlaneOrigin = Shader.PropertyToID("_Udon_Plane_Origin_" + idx.ToString());
int idPlaneUinv = Shader.PropertyToID("_Udon_Plane_Uinv_" + idx.ToString());
int idPlaneVinv = Shader.PropertyToID("_Udon_Plane_Vinv_" + idx.ToString());
int idPlaneNormal = Shader.PropertyToID("_Udon_Plane_Normal_" + idx.ToString());
Vector4 origin = new Vector4(t.position.x, t.position.y, t.position.z, 0);
Vector4 uinv4 = new Vector4(Uinv.x, Uinv.y, Uinv.z, 0);
Vector4 vinv4 = new Vector4(Vinv.x, Vinv.y, Vinv.z, 0);
Vector4 n4 = new Vector4(N.x, N.y, N.z, 0);
for (int r = 0; r < targets.Length; r++)
{ {
_propId[b] = newId; var ren = targets[r];
id = newId; if (ren == null) continue;
}
return id;
}
static void ApplyToBehaviour(ShadowcasterUpdater b) ren.GetPropertyBlock(_mpb);
{
var renderers = b.rendererTargets;
if (renderers == null || renderers.Length == 0) return;
int id = GetPropertyId(b); // Also mirror texture/color in case ApplyTextureData couldn't run
Matrix4x4 w2l = b.transform.worldToLocalMatrix; if (u.ShadowcasterTexture != null) _mpb.SetTexture(idShadowTex, u.ShadowcasterTexture);
_mpb.SetColor(idShadowColor, u.TextureColor);
_mpb.SetColor(idOutsideColor, u.OutsideColor);
_mpb.SetFloat(idMinBrightness, u.MinBrightness);
for (int i = 0; i < renderers.Length; i++) // Plane data
{ _mpb.SetVector(idPlaneOrigin, origin);
Renderer r = renderers[i]; _mpb.SetVector(idPlaneUinv, uinv4);
if (r == null) continue; _mpb.SetVector(idPlaneVinv, vinv4);
_mpb.SetVector(idPlaneNormal, n4);
if (_lastW2L.TryGetValue(r, out var last) && last == w2l) ren.SetPropertyBlock(_mpb);
continue; // nothing changed for this renderer
r.GetPropertyBlock(sMPB);
sMPB.SetMatrix(id, w2l);
r.SetPropertyBlock(sMPB);
_lastW2L[r] = w2l;
}
}
}
[CustomEditor(typeof(ShadowcasterUpdater))]
public class ShadowcasterUpdaterInspector : Editor
{
public override void OnInspectorGUI()
{
DrawDefaultInspector();
GUILayout.Space(6);
using (new EditorGUI.DisabledScope(true))
{
EditorGUILayout.LabelField("Edit-Mode Preview", EditorStyles.boldLabel);
EditorGUILayout.LabelField("Keeps the matrix property updated in the Scene View.");
}
if (GUILayout.Button("Refresh Now"))
{
ShadowcasterUpdaterPreview.ForceTick();
EditorApplication.QueuePlayerLoopUpdate();
SceneView.RepaintAll();
} }
} }
} }

View File

@@ -16,7 +16,6 @@ public class ShadowcasterUpdater : UdonSharpBehaviour
public int shadowcasterIndex = 1; public int shadowcasterIndex = 1;
public string propertyName = "_Udon_WorldToLocal";
private MaterialPropertyBlock _mpb; private MaterialPropertyBlock _mpb;
@@ -32,23 +31,44 @@ public class ShadowcasterUpdater : UdonSharpBehaviour
{ {
if (mat == null) continue; if (mat == null) continue;
mat.GetPropertyBlock(_mpb); mat.GetPropertyBlock(_mpb);
_mpb.SetTexture("_Udon_ShadowcasterTex" + "_" + (string)shadowcasterIndex, ShadowcasterTexture); _mpb.SetTexture("_Udon_shadowCasterTex" + "_" + shadowcasterIndex.ToString(), ShadowcasterTexture);
_mpb.SetColor("_Udon_shadowCasterColor" + "_" + (string)shadowcasterIndex, TextureColor); _mpb.SetColor("_Udon_shadowCasterColor" + "_" + shadowcasterIndex.ToString(), TextureColor);
_mpb.SetColor("_Udon_OutSideColor" + "_" + (string)shadowcasterIndex, OutsideColor); _mpb.SetColor("_Udon_OutSideColor" + "_" + shadowcasterIndex.ToString(), OutsideColor);
_mpb.SetFloat("_Udon_MinBrightnessShadow" + "_" + (string)shadowcasterIndex, MinBrightness); _mpb.SetFloat("_Udon_MinBrightnessShadow" + "_" + shadowcasterIndex.ToString(), MinBrightness);
mat.SetPropertyBlock(_mpb); mat.SetPropertyBlock(_mpb);
} }
} }
void LateUpdate() void LateUpdate()
{ {
var w2l = transform.worldToLocalMatrix;
foreach (Renderer mat in rendererTargets) foreach (Renderer mat in rendererTargets)
{ {
if (mat == null) continue; if (mat == null) continue;
mat.GetPropertyBlock(_mpb); mat.GetPropertyBlock(_mpb);
_mpb.SetMatrix(propertyName + "_" + (string)shadowcasterIndex, w2l);
float quadHalfWidth = 0.5f;
float quadHalfHeight = 0.5f;
// World-space basis directions from transform
Vector3 Udir = transform.rotation * Vector3.right; // plane local +X
Vector3 Vdir = transform.rotation * Vector3.up; // plane local +Y
// World-space half extents after non-uniform scaling
float halfW = quadHalfWidth * transform.lossyScale.x;
float halfH = quadHalfHeight * transform.lossyScale.y;
// Reciprocal axes so dot(r, Uinv/Vinv) -> [-0.5, 0.5]
Vector3 Uinv = Udir / (2.0f * Mathf.Max(halfW, 1e-6f));
Vector3 Vinv = Vdir / (2.0f * Mathf.Max(halfH, 1e-6f));
// Unit normal
Vector3 N = Vector3.Normalize(Vector3.Cross(Udir, Vdir));
_mpb.SetVector("_Udon_Plane_Origin_" + shadowcasterIndex.ToString(), new Vector4(transform.position.x, transform.position.y, transform.position.z, 0));
_mpb.SetVector("_Udon_Plane_Uinv_" + shadowcasterIndex.ToString(), new Vector4(Uinv.x, Uinv.y, Uinv.z, 0));
_mpb.SetVector("_Udon_Plane_Vinv_" + shadowcasterIndex.ToString(), new Vector4(Vinv.x, Vinv.y, Vinv.z, 0));
_mpb.SetVector("_Udon_Plane_Normal_" + shadowcasterIndex.ToString(), new Vector4(N.x, N.y, N.z, 0));
mat.SetPropertyBlock(_mpb); mat.SetPropertyBlock(_mpb);
} }

View File

@@ -86,13 +86,22 @@ Shader "DeMuenu/World/Hoppou/RevealStandart"
MoonlightGlobalVariables MoonlightGlobalVariables
float4x4 _Udon_WorldToLocal_1;
float4 _Udon_Plane_Origin_1; // xyz = origin (world), w unused
float4 _Udon_Plane_Uinv_1; // xyz = Udir / (2*halfWidth)
float4 _Udon_Plane_Vinv_1; // xyz = Vdir / (2*halfHeight)
float4 _Udon_Plane_Normal_1; // xyz = unit normal
sampler2D _Udon_shadowCasterTex_1; sampler2D _Udon_shadowCasterTex_1;
float4 _Udon_shadowCasterColor_1; float4 _Udon_shadowCasterColor_1;
float4 _Udon_OutSideColor_1; float4 _Udon_OutSideColor_1;
float _Udon_MinBrightnessShadow_1; float _Udon_MinBrightnessShadow_1;
float4x4 _Udon_WorldToLocal_2; float4 _Udon_Plane_Origin_2;
float4 _Udon_Plane_Uinv_2;
float4 _Udon_Plane_Vinv_2;
float4 _Udon_Plane_Normal_2;
sampler2D _Udon_shadowCasterTex_2; sampler2D _Udon_shadowCasterTex_2;
float4 _Udon_shadowCasterColor_2; float4 _Udon_shadowCasterColor_2;
float4 _Udon_OutSideColor_2; float4 _Udon_OutSideColor_2;
@@ -153,19 +162,25 @@ Shader "DeMuenu/World/Hoppou/RevealStandart"
LightTypeCalculations(_Udon_LightColors, LightCounter, i, NdotL, dIntensity, _Udon_LightPositions[LightCounter].a, _Udon_LightPositions[LightCounter].xyz); LightTypeCalculations(_Udon_LightColors, LightCounter, i, NdotL, dIntensity, _Udon_LightPositions[LightCounter].a, _Udon_LightPositions[LightCounter].xyz);
float4 ShadowCasterMult_1 = float4(1,1,1,1); float4 ShadowCasterMult_1 = 1;
float4 ShadowCasterMult_2 = float4(1,1,1,1); float4 ShadowCasterMult_2 = 1;
if (((_Udon_ShadowMapIndex[LightCounter] > 0.5) && (_Udon_ShadowMapIndex[LightCounter] < 1.5)) || (_Udon_ShadowMapIndex[LightCounter] > 2.5)) {
ShadowCasterMult_1 = SampleShadowcasterPlane(_Udon_WorldToLocal_1, _Udon_shadowCasterTex_1, _Udon_LightPositions[LightCounter].xyz, i.worldPos, _Udon_OutSideColor_1); if (((_Udon_ShadowMapIndex[LightCounter] > 0.5) && (_Udon_ShadowMapIndex[LightCounter] < 1.5)) || (_Udon_ShadowMapIndex[LightCounter] > 2.5))
ShadowCasterMult_1 *= _Udon_shadowCasterColor_1; {
ShadowCasterMult_1 = float4(ShadowCasterMult_1.rgb * (1-ShadowCasterMult_1.a), 1); float4 sc1 = SampleShadowcasterPlaneWS_Basis(
ShadowCasterMult_1 = max(ShadowCasterMult_1, _Udon_MinBrightnessShadow_1) _Udon_LightPositions[LightCounter].xyz, i.worldPos,
_Udon_Plane_Origin_1.xyz, _Udon_Plane_Uinv_1.xyz, _Udon_Plane_Vinv_1.xyz, _Udon_Plane_Normal_1.xyz,
_Udon_shadowCasterTex_1, _Udon_OutSideColor_1, _Udon_shadowCasterColor_1);
ShadowCasterMult_1 = max(sc1, _Udon_MinBrightnessShadow_1);
} }
if (_Udon_ShadowMapIndex[LightCounter] > 1.5) {
ShadowCasterMult_2 = SampleShadowcasterPlane(_Udon_WorldToLocal_2, _Udon_shadowCasterTex_2, _Udon_LightPositions[LightCounter].xyz, i.worldPos, _Udon_OutSideColor_2); if (_Udon_ShadowMapIndex[LightCounter] > 1.5)
ShadowCasterMult_2 *= _Udon_shadowCasterColor_2; {
ShadowCasterMult_2 = float4(ShadowCasterMult_2.rgb * (1-ShadowCasterMult_2.a), 1); float4 sc2 = SampleShadowcasterPlaneWS_Basis(
ShadowCasterMult_2 = max(ShadowCasterMult_2, _Udon_MinBrightnessShadow_2) _Udon_LightPositions[LightCounter].xyz, i.worldPos,
_Udon_Plane_Origin_2.xyz, _Udon_Plane_Uinv_2.xyz, _Udon_Plane_Vinv_2.xyz, _Udon_Plane_Normal_2.xyz,
_Udon_shadowCasterTex_2, _Udon_OutSideColor_2, _Udon_shadowCasterColor_2);
ShadowCasterMult_2 = max(sc2, _Udon_MinBrightnessShadow_2);
} }
dmax = dmax + contrib * float4(LightColor, 1) * ShadowCasterMult_1 * ShadowCasterMult_2; dmax = dmax + contrib * float4(LightColor, 1) * ShadowCasterMult_1 * ShadowCasterMult_2;

View File

@@ -3,54 +3,30 @@
#include "UnityCG.cginc" // for tex2Dlod, etc. #include "UnityCG.cginc" // for tex2Dlod, etc.
static const float EPS = 1e-5; static const float WS_EPS = 1e-5;
// Returns whether segment hits the unit plane quad in plane-local z=0. inline float4 SampleShadowcasterPlaneWS_Basis(
// Outputs uv in [0,1] and t in [0,1] along A->B. float3 A, float3 B,
inline bool RaySegmentHitsPlaneQuad(float4x4 worldToLocal, float3 rayOrigin, float3 rayEnd, out float2 uv, out float t) float3 P0, float3 Uinv, float3 Vinv, float3 N,
sampler2D tex, float4 OutsideColor, float4 ShadowColor)
{ {
float3 aP = mul(worldToLocal, float4(rayOrigin, 1)).xyz; float3 d = B - A;
float3 bP = mul(worldToLocal, float4(rayEnd, 1)).xyz; float dn = dot(N, d);
if (abs(dn) < WS_EPS) return OutsideColor;
float3 d = bP - aP; float t = dot(N, P0 - A) / dn;
float dz = d.z; if (t < 0.0 || t > 1.0) return OutsideColor;
float3 hit = A + d * t;
float3 r = hit - P0;
// Parallel-ish to plane? // u,v in [-0.5, 0.5] if inside quad
if (abs(dz) < EPS) return false; float u = dot(r, Uinv);
float v = dot(r, Vinv);
if (abs(u) > 0.5 || abs(v) > 0.5) return OutsideColor;
// Intersect z=0 float4 returnColor = tex2D(tex, float2(u + 0.5, v + 0.5)) * ShadowColor;
t = -aP.z / dz; returnColor = float4(returnColor.rgb * (1 - returnColor.a), 1);
return returnColor;
// Segment only
if (t < 0.0 || t > 1.0) return false;
float3 hit = aP + d * t;
// Inside 1x1 centered quad?
if (abs(hit.x) > 0.5 || abs(hit.y) > 0.5) return false;
uv = hit.xy + 0.5; // [-0.5,0.5] -> [0,1]
return true;
}
// Fragment-shader version: uses proper filtering/mips via tex2D
inline float4 SampleShadowcasterPlane(float4x4 worldToLocal, sampler2D tex, float3 rayOrigin, float3 rayEnd, float4 OutsideColor)
{
float2 uv; float t;
if (RaySegmentHitsPlaneQuad(worldToLocal, rayOrigin, rayEnd, uv, t))
return tex2D(tex, uv); // full color
return OutsideColor;
}
// Anywhere (vertex/geom/compute/custom code) version: forces LOD 0
inline float4 SampleShadowcasterPlaneLOD0(float4x4 worldToLocal, sampler2D tex, float3 rayOrigin, float3 rayEnd, float4 OutsideColor)
{
float2 uv; float t;
if (RaySegmentHitsPlaneQuad(worldToLocal, rayOrigin, rayEnd, uv, t))
return tex2Dlod(tex, float4(uv, 0, 0)); // full color at mip 0
return OutsideColor;
} }
#endif #endif

View File

@@ -79,18 +79,25 @@ Shader "DeMuenu/World/Hoppou/Particles/LitParticles"
MoonlightGlobalVariables MoonlightGlobalVariables
float4x4 _Udon_WorldToLocal_1; float4 _Udon_Plane_Origin_1; // xyz = origin (world), w unused
float4 _Udon_Plane_Uinv_1; // xyz = Udir / (2*halfWidth)
float4 _Udon_Plane_Vinv_1; // xyz = Vdir / (2*halfHeight)
float4 _Udon_Plane_Normal_1; // xyz = unit normal
sampler2D _Udon_shadowCasterTex_1; sampler2D _Udon_shadowCasterTex_1;
float4 _Udon_shadowCasterColor_1; float4 _Udon_shadowCasterColor_1;
float4 _Udon_OutSideColor_1; float4 _Udon_OutSideColor_1;
float _Udon_MinBrightnessShadow_1; float _Udon_MinBrightnessShadow_1;
float4x4 _Udon_WorldToLocal_2; float4 _Udon_Plane_Origin_2;
float4 _Udon_Plane_Uinv_2;
float4 _Udon_Plane_Vinv_2;
float4 _Udon_Plane_Normal_2;
sampler2D _Udon_shadowCasterTex_2; sampler2D _Udon_shadowCasterTex_2;
float4 _Udon_shadowCasterColor_2; float4 _Udon_shadowCasterColor_2;
float4 _Udon_OutSideColor_2; float4 _Udon_OutSideColor_2;
float _Udon_MinBrightnessShadow_2; float _Udon_MinBrightnessShadow_2;
v2f vert (appdata v) v2f vert (appdata v)
{ {
v2f o; v2f o;
@@ -129,22 +136,28 @@ Shader "DeMuenu/World/Hoppou/Particles/LitParticles"
LightTypeCalculations(_Udon_LightColors, LightCounter, i, 1, dIntensity, _Udon_LightPositions[LightCounter].a, _Udon_LightPositions[LightCounter].xyz); LightTypeCalculations(_Udon_LightColors, LightCounter, i, 1, dIntensity, _Udon_LightPositions[LightCounter].a, _Udon_LightPositions[LightCounter].xyz);
float4 ShadowCasterMult_1 = float4(1,1,1,1); float4 ShadowCasterMult_1 = 1;
float4 ShadowCasterMult_2 = float4(1,1,1,1); float4 ShadowCasterMult_2 = 1;
if (((_Udon_ShadowMapIndex[LightCounter] > 0.5) && (_Udon_ShadowMapIndex[LightCounter] < 1.5)) || (_Udon_ShadowMapIndex[LightCounter] > 2.5)) {
ShadowCasterMult_1 = SampleShadowcasterPlane(_Udon_WorldToLocal_1, _Udon_shadowCasterTex_1, _Udon_LightPositions[LightCounter].xyz, i.worldPos, _Udon_OutSideColor_1); if (((_Udon_ShadowMapIndex[LightCounter] > 0.5) && (_Udon_ShadowMapIndex[LightCounter] < 1.5)) || (_Udon_ShadowMapIndex[LightCounter] > 2.5))
ShadowCasterMult_1 *= _Udon_shadowCasterColor_1; {
ShadowCasterMult_1 = float4(ShadowCasterMult_1.rgb * (1-ShadowCasterMult_1.a), 1); float4 sc1 = SampleShadowcasterPlaneWS_Basis(
ShadowCasterMult_1 = max(ShadowCasterMult_1, _Udon_MinBrightnessShadow_1) _Udon_LightPositions[LightCounter].xyz, i.worldPos,
} _Udon_Plane_Origin_1.xyz, _Udon_Plane_Uinv_1.xyz, _Udon_Plane_Vinv_1.xyz, _Udon_Plane_Normal_1.xyz,
if (_Udon_ShadowMapIndex[LightCounter] > 1.5) { _Udon_shadowCasterTex_1, _Udon_OutSideColor_1, _Udon_shadowCasterColor_1);
ShadowCasterMult_2 = SampleShadowcasterPlane(_Udon_WorldToLocal_2, _Udon_shadowCasterTex_2, _Udon_LightPositions[LightCounter].xyz, i.worldPos, _Udon_OutSideColor_2); ShadowCasterMult_1 = max(sc1, _Udon_MinBrightnessShadow_1);
ShadowCasterMult_2 *= _Udon_shadowCasterColor_2;
ShadowCasterMult_2 = float4(ShadowCasterMult_2.rgb * (1-ShadowCasterMult_2.a), 1);
ShadowCasterMult_2 = max(ShadowCasterMult_2, _Udon_MinBrightnessShadow_2)
} }
dmax = dmax + contrib * float4(LightColor, 1) * ShadowCasterMult1 * ShadowCasterMult_2; if (_Udon_ShadowMapIndex[LightCounter] > 1.5)
{
float4 sc2 = SampleShadowcasterPlaneWS_Basis(
_Udon_LightPositions[LightCounter].xyz, i.worldPos,
_Udon_Plane_Origin_2.xyz, _Udon_Plane_Uinv_2.xyz, _Udon_Plane_Vinv_2.xyz, _Udon_Plane_Normal_2.xyz,
_Udon_shadowCasterTex_2, _Udon_OutSideColor_2, _Udon_shadowCasterColor_2);
ShadowCasterMult_2 = max(sc2, _Udon_MinBrightnessShadow_2);
}
dmax = dmax + contrib * float4(LightColor, 1) * ShadowCasterMult_1 * ShadowCasterMult_2;
} }