From a1e808ad92d9dda0e1485f268247022155e99d8b Mon Sep 17 00:00:00 2001 From: DeMuenu <96650288+DeMuenu@users.noreply.github.com> Date: Tue, 24 Mar 2026 15:45:31 +0100 Subject: [PATCH 1/6] optimisations from gemini (not tested) --- EditorPreview/LightUpdater.Editor.cs | 25 +++++---- README.md | 2 +- Scripts/LightUpdater.cs | 67 ++++++++++++++++++++---- Scripts/LightdataStorage.cs | 22 +++++++- Scripts/ShadowcasterUpdater.cs | 78 ++++++++++++++++++---------- Shader/Includes/DefaultSetup.hlsl | 8 ++- Shader/Includes/Lambert.hlsl | 4 +- Shader/Includes/LightStrength.hlsl | 16 +++--- Shader/LitParticles_2SP.shader | 31 ++++++----- Shader/Standard_2SP.shader | 32 +++++++----- Shader/Standard_Lightmap_2SP.shader | 32 +++++++----- Shader/Water_2SP.shader | 31 ++++++----- 12 files changed, 231 insertions(+), 117 deletions(-) diff --git a/EditorPreview/LightUpdater.Editor.cs b/EditorPreview/LightUpdater.Editor.cs index 3161938..4e6a036 100644 --- a/EditorPreview/LightUpdater.Editor.cs +++ b/EditorPreview/LightUpdater.Editor.cs @@ -21,38 +21,37 @@ public partial class LightUpdater shadowMapIndices = new float[max]; count = 0; - if (otherLightSources == null) return; + LightdataStorage[] sceneLights = Object.FindObjectsOfType(); - for (int i = 0; i < otherLightSources.Length && count < max; i++) + for (int i = 0; i < sceneLights.Length && count < max; i++) { - Transform t = otherLightSources[i]; - if (t == null || !t.gameObject.activeInHierarchy) continue; + LightdataStorage data = sceneLights[i]; + if (data == null || !data.gameObject.activeInHierarchy) continue; - LightdataStorage data = t.GetComponent(); + Transform t = data.transform; // w = cosHalfAngle (0 for omni) - float cosHalf = (data != null) ? data.GetCosHalfAngle() : 0f; + float cosHalf = data.GetCosHalfAngle(); Vector3 pos = t.position; float range = 0; if (data.lightType == LightType.Sphere) { - range = (data != null) ? data.range * t.localScale.x : t.localScale.x; + range = data.range * t.localScale.x; } else { - range = (data != null) ? Mathf.Cos(Mathf.Deg2Rad * ((data.spotAngleDeg * 0.5f) + Mathf.Max(data.range, 0))): 0f; + range = Mathf.Cos(Mathf.Deg2Rad * ((data.spotAngleDeg * 0.5f) + Mathf.Max(data.range, 0))); } // rgb = color, a = intensity (packed to match runtime/shader) - Vector4 col = (data != null) ? data.GetFinalColor() : new Vector4(1f, 1f, 1f, 1f); - float intensity = (data != null) ? data.intensity * t.localScale.x : 1f; - + Vector4 col = data.GetFinalColor(); + float intensity = data.intensity * t.localScale.x; // 0=Omni, 1=Spot, 2=Directional (your custom enum) - int typeId = (data != null) ? data.GetTypeId() : 0; + int typeId = data.GetTypeId(); - float shIndex = (data != null) ? data.shadowMapIndex : 0f; + float shIndex = data.shadowMapIndex; Quaternion rot = t.rotation; Vector3 fwd = rot * Vector3.down; diff --git a/README.md b/README.md index 7cc19ef..ba16da0 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ On PC, I haven't encountered any frame drops in the editor at all, even with 400 3. For lights, attach `LightdataStorage` to a Transform and configure: - `range`, `type`, `color`, `intensity`, and `spotAngleDeg`. -4. Add the light transform to your `LightUpdater` component's `otherLightSources` array. +4. On your light's `LightdataStorage` component, assign your scene's `LightUpdater` to the `Light Updater` field. This allows lights to be added or removed dynamically at runtime. 5. Use one of the premade shaders on your material. Or, if you feel like it, use the provided .hlsl/.cginc in your own shader. You just need to copy everything surrounded by Moonlight comments, and apply it at the end of your shader. diff --git a/Scripts/LightUpdater.cs b/Scripts/LightUpdater.cs index 2c4a7fb..df0f2f7 100644 --- a/Scripts/LightUpdater.cs +++ b/Scripts/LightUpdater.cs @@ -1,4 +1,5 @@ using System; +using System; using UdonSharp; using Unity.Mathematics; using UnityEngine; @@ -9,9 +10,6 @@ using VRC.SDK3.Rendering; public partial class LightUpdater : UdonSharpBehaviour { [Header("Lightsources")] - [Tooltip("Place Transforms here which should also emit Light (attach LightdataStorage to them).")] - public Transform[] otherLightSources; - [Header("Strength")] [Tooltip("Local player light range")] @@ -68,6 +66,9 @@ public partial class LightUpdater : UdonSharpBehaviour private float[] _ShadowMapArray; private bool _ShadowMap_isDirty = false; + private LightdataStorage[] _sceneLights; + private int _sceneLightCount = 0; + private VRCPlayerApi[] _players; @@ -91,6 +92,7 @@ public partial class LightUpdater : UdonSharpBehaviour _directions = new Vector4[maxLights]; _TypeArray = new float[maxLights]; _ShadowMapArray = new float[maxLights]; + _sceneLights = new LightdataStorage[maxLights]; _players = new VRCPlayerApi[maxLights]; @@ -101,11 +103,56 @@ public partial class LightUpdater : UdonSharpBehaviour UdonID_LightType = VRCShader.PropertyToID(typeProperty); UdonID_ShadowMapIndex = VRCShader.PropertyToID(shadowMapIndexProperty); - UpdateData(); PushToRenderers(); } + public void RegisterLight(LightdataStorage light) + { + if (light == null) return; + + // Prevent duplicates + for (int i = 0; i < _sceneLightCount; i++) + { + if (_sceneLights[i] == light) return; + } + + if (_sceneLightCount < _sceneLights.Length) + { + _sceneLights[_sceneLightCount] = light; + _sceneLightCount++; + } + else + { + Debug.LogError($"[MoonlightVRC] Cannot register new light, scene light limit reached ({_sceneLights.Length})"); + } + } + + public void DeregisterLight(LightdataStorage light) + { + if (light == null) return; + int foundIndex = -1; + for (int i = 0; i < _sceneLightCount; i++) + { + if (_sceneLights[i] == light) + { + foundIndex = i; + break; + } + } + + if (foundIndex != -1) + { + // Shift elements down to fill the gap + for (int i = foundIndex; i < _sceneLightCount - 1; i++) + { + _sceneLights[i] = _sceneLights[i + 1]; + } + _sceneLightCount--; + _sceneLights[_sceneLightCount] = null; // Clear the last element + } + } + void LateUpdate() { if (Time.time < _nextUpdate) return; @@ -154,6 +201,7 @@ public partial class LightUpdater : UdonSharpBehaviour if (_directions[i] != TempDir) { _directions[i] = new Vector4(TempDir.x, TempDir.y, TempDir.z, 10f); + _directions[i] = TempDir; _directions_isDirty = true; } @@ -201,14 +249,13 @@ public partial class LightUpdater : UdonSharpBehaviour } // --- Scene light sources --- - if (otherLightSources != null) + if (_sceneLights != null) { - for (int j = 0; j < otherLightSources.Length && currentCount < maxLights; j++) + for (int j = 0; j < _sceneLightCount && currentCount < maxLights; j++) { - Transform t = otherLightSources[j]; - if (t == null || !t.gameObject.activeInHierarchy) continue; - - LightdataStorage data = t.GetComponent(); + LightdataStorage data = _sceneLights[j]; + if (data == null || !data.gameObject.activeInHierarchy) continue; + Transform t = data.transform; Vector3 pos = t.position; float range = (data != null) ? data.range * t.localScale.x: t.localScale.x; diff --git a/Scripts/LightdataStorage.cs b/Scripts/LightdataStorage.cs index 3c547d5..a1a9ee4 100644 --- a/Scripts/LightdataStorage.cs +++ b/Scripts/LightdataStorage.cs @@ -1,4 +1,4 @@ -using UdonSharp; +using UdonSharp; using UnityEngine; using VRC.SDKBase; using VRC.Udon; @@ -10,6 +10,10 @@ public enum LightType { Sphere, Spot } [UdonBehaviourSyncMode(BehaviourSyncMode.None)] public class LightdataStorage : UdonSharpBehaviour { + [Header("System")] + [Tooltip("The main LightUpdater in the scene. This is required for dynamic lights.")] + public LightUpdater lightUpdater; + [Header("Type")] [Tooltip("Select the logical light type for this source.")] @@ -36,6 +40,22 @@ public class LightdataStorage : UdonSharpBehaviour [Tooltip("0 = no shadows, 1-4 = shadow map index")] public float shadowMapIndex = 0f; // 0 = no shadows, 1-4 = shadow map index + void OnEnable() + { + if (lightUpdater != null) + { + lightUpdater.RegisterLight(this); + } + } + + void OnDisable() + { + if (lightUpdater != null) + { + lightUpdater.DeregisterLight(this); + } + } + // Convert to a Vector4 for your shader upload public Vector4 GetFinalColor() { diff --git a/Scripts/ShadowcasterUpdater.cs b/Scripts/ShadowcasterUpdater.cs index 14c11cb..1ae803e 100644 --- a/Scripts/ShadowcasterUpdater.cs +++ b/Scripts/ShadowcasterUpdater.cs @@ -1,4 +1,4 @@ - + using System.Security.Permissions; using UdonSharp; using UnityEngine; @@ -18,10 +18,30 @@ public class ShadowcasterUpdater : UdonSharpBehaviour private MaterialPropertyBlock _mpb; + private int _propShadowTex; + private int _propShadowColor; + private int _propOutsideColor; + private int _propMinBrightness; + private int _propPlaneOrigin; + private int _propPlaneUinv; + private int _propPlaneVinv; + private int _propPlaneNormal; void Start() { _mpb = new MaterialPropertyBlock(); + + string suf = "_" + shadowcasterIndex.ToString(); + _propShadowTex = VRCShader.PropertyToID("_Udon_shadowCasterTex" + suf); + _propShadowColor = VRCShader.PropertyToID("_Udon_shadowCasterColor" + suf); + _propOutsideColor = VRCShader.PropertyToID("_Udon_OutSideColor" + suf); + _propMinBrightness = VRCShader.PropertyToID("_Udon_MinBrightnessShadow" + suf); + + _propPlaneOrigin = VRCShader.PropertyToID("_Udon_Plane_Origin" + suf); + _propPlaneUinv = VRCShader.PropertyToID("_Udon_Plane_Uinv" + suf); + _propPlaneVinv = VRCShader.PropertyToID("_Udon_Plane_Vinv" + suf); + _propPlaneNormal = VRCShader.PropertyToID("_Udon_Plane_Normal" + suf); + ApplyTextureData(); } @@ -31,43 +51,47 @@ public class ShadowcasterUpdater : UdonSharpBehaviour { if (mat == null) continue; mat.GetPropertyBlock(_mpb); - _mpb.SetTexture("_Udon_shadowCasterTex" + "_" + shadowcasterIndex.ToString(), ShadowcasterTexture); - _mpb.SetColor("_Udon_shadowCasterColor" + "_" + shadowcasterIndex.ToString(), TextureColor); - _mpb.SetColor("_Udon_OutSideColor" + "_" + shadowcasterIndex.ToString(), OutsideColor); - _mpb.SetFloat("_Udon_MinBrightnessShadow" + "_" + shadowcasterIndex.ToString(), MinBrightness); + if (ShadowcasterTexture != null) _mpb.SetTexture(_propShadowTex, ShadowcasterTexture); + _mpb.SetColor(_propShadowColor, TextureColor); + _mpb.SetColor(_propOutsideColor, OutsideColor); + _mpb.SetFloat(_propMinBrightness, MinBrightness); mat.SetPropertyBlock(_mpb); } } void LateUpdate() { + 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)); + + Vector4 originVec = new Vector4(transform.position.x, transform.position.y, transform.position.z, 0); + Vector4 uinvVec = new Vector4(Uinv.x, Uinv.y, Uinv.z, 0); + Vector4 vinvVec = new Vector4(Vinv.x, Vinv.y, Vinv.z, 0); + Vector4 nVec = new Vector4(N.x, N.y, N.z, 0); foreach (Renderer mat in rendererTargets) { if (mat == null) continue; mat.GetPropertyBlock(_mpb); - 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)); + _mpb.SetVector(_propPlaneOrigin, originVec); + _mpb.SetVector(_propPlaneUinv, uinvVec); + _mpb.SetVector(_propPlaneVinv, vinvVec); + _mpb.SetVector(_propPlaneNormal, nVec); mat.SetPropertyBlock(_mpb); } diff --git a/Shader/Includes/DefaultSetup.hlsl b/Shader/Includes/DefaultSetup.hlsl index 6c3b1f5..3ba5a65 100644 --- a/Shader/Includes/DefaultSetup.hlsl +++ b/Shader/Includes/DefaultSetup.hlsl @@ -2,16 +2,20 @@ #define InLoopSetup(_Udon_LightPositions, LightCounter, count, i) \ if (LightCounter >= count) break; \ \ - float distanceFromLight = length(i.worldPos - _Udon_LightPositions[LightCounter].xyz); \ + float3 lightVec = _Udon_LightPositions[LightCounter].xyz - i.worldPos; \ + float distanceFromLight = length(lightVec); \ if (distanceFromLight > _LightCutoffDistance) continue; \ \ - float contrib = 0.0; + float contrib = 0.0; \ + float3 L = lightVec / max(distanceFromLight, 1e-4); #endif #ifndef OutLoopSetup #define OutLoopSetup(i, _Udon_PlayerCount) \ int count = (int)_Udon_PlayerCount; \ + float invSqMul = max(1e-4, _InverseSqareMultiplier); \ + bool shadowCastingEnabled = _EnableShadowCasting > 0.5; \ \ float4 dmax = float4(0,0,0,1); \ float dIntensity = 0; diff --git a/Shader/Includes/Lambert.hlsl b/Shader/Includes/Lambert.hlsl index 1a8d7df..75db42b 100644 --- a/Shader/Includes/Lambert.hlsl +++ b/Shader/Includes/Lambert.hlsl @@ -1,7 +1,7 @@ #ifndef Lambert #define Lambert(q ,i, N) \ - float3 L = normalize(q - i.worldPos); /* q = light position */ \ - float NdotL = saturate(dot(N, L) * 0.5 + 0.5); /* one-sided Lambert */ \ + /* 'L' is inherited from InLoopSetup, avoiding an expensive normalize() */ \ + half NdotL = saturate(dot(N, L) * 0.5 + 0.5); /* one-sided Lambert */ \ if (NdotL <= 0) continue; \ #endif \ No newline at end of file diff --git a/Shader/Includes/LightStrength.hlsl b/Shader/Includes/LightStrength.hlsl index cd53b39..28dcfcb 100644 --- a/Shader/Includes/LightStrength.hlsl +++ b/Shader/Includes/LightStrength.hlsl @@ -1,24 +1,26 @@ #ifndef LightTypeCalculations #define LightTypeCalculations(_Udon_LightColors ,LightCounter, i, NdotL, dIntensity, radius, Lightposition) \ - float invSqMul = max(1e-4, _InverseSqareMultiplier); \ + half typeId = _Udon_LightType[LightCounter]; \ \ - if(_Udon_LightType[LightCounter] == 0) \ + if(typeId == 0) \ { \ - contrib = _Udon_LightColors[LightCounter].a / max(1e-4, max(0, max(1, distanceFromLight - radius) * invSqMul) * max(0, max(1, distanceFromLight - radius) * invSqMul)); \ + float distAtten = max(1.0, distanceFromLight - radius) * invSqMul; \ + contrib = _Udon_LightColors[LightCounter].a / max(1e-4, distAtten * distAtten); \ \ dIntensity += contrib; \ } \ - else if (_Udon_LightType[LightCounter] == 1) \ + else if (typeId == 1) \ { \ - float invSq = _Udon_LightColors[LightCounter].a / max(1e-4, (distanceFromLight * invSqMul) * (distanceFromLight * invSqMul)); \ + float distAtten = distanceFromLight * invSqMul; \ + float invSq = _Udon_LightColors[LightCounter].a / max(1e-4, distAtten * distAtten); \ \ - contrib = dot(normalize(i.worldPos - Lightposition), normalize(_Udon_LightDirections[LightCounter].xyz)); \ + contrib = dot(-L, normalize(_Udon_LightDirections[LightCounter].xyz)); \ contrib = smoothstep(radius,_Udon_LightDirections[LightCounter].w, contrib); \ \ contrib = contrib * invSq; \ dIntensity += contrib; \ } \ - float3 LightColor = _Udon_LightColors[LightCounter].xyz; \ + half3 LightColor = _Udon_LightColors[LightCounter].xyz; \ #endif \ No newline at end of file diff --git a/Shader/LitParticles_2SP.shader b/Shader/LitParticles_2SP.shader index 9bd04e7..03b0658 100644 --- a/Shader/LitParticles_2SP.shader +++ b/Shader/LitParticles_2SP.shader @@ -149,20 +149,25 @@ Shader "DeMuenu/World/Hoppou/Particles/LitParticles_2SP" float4 ShadowCasterMult_1 = 1; float4 ShadowCasterMult_2 = 1; - if (((_Udon_ShadowMapIndex[LightCounter] > 0.5) && (_Udon_ShadowMapIndex[LightCounter] < 1.5) && (_EnableShadowCasting > 0.5)) || (_Udon_ShadowMapIndex[LightCounter] > 2.5 && _EnableShadowCasting)) + if (shadowCastingEnabled) { - float4 sc1 = SampleShadowcasterPlaneWS_Basis( - _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, _BlurPixels, _Udon_shadowCasterTex_1_TexelSize.xy); - ShadowCasterMult_1 = max(sc1, _Udon_MinBrightnessShadow_1); - } - if (_Udon_ShadowMapIndex[LightCounter] > 1.5 && (_EnableShadowCasting > 0.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, _BlurPixels, _Udon_shadowCasterTex_2_TexelSize.xy); - ShadowCasterMult_2 = max(sc2, _Udon_MinBrightnessShadow_2); + half smIndex = _Udon_ShadowMapIndex[LightCounter]; + if ((smIndex > 0.5 && smIndex < 1.5) || smIndex > 2.5) + { + float4 sc1 = SampleShadowcasterPlaneWS_Basis( + _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, _BlurPixels, _Udon_shadowCasterTex_1_TexelSize.xy); + ShadowCasterMult_1 = max(sc1, _Udon_MinBrightnessShadow_1); + } + if (smIndex > 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, _BlurPixels, _Udon_shadowCasterTex_2_TexelSize.xy); + ShadowCasterMult_2 = max(sc2, _Udon_MinBrightnessShadow_2); + } } dmax = dmax + contrib * float4(LightColor, 1) * ShadowCasterMult_1 * ShadowCasterMult_2; diff --git a/Shader/Standard_2SP.shader b/Shader/Standard_2SP.shader index 6355548..cbb91b1 100644 --- a/Shader/Standard_2SP.shader +++ b/Shader/Standard_2SP.shader @@ -176,21 +176,25 @@ Shader "DeMuenu/World/Hoppou/Standard_2SP" float4 ShadowCasterMult_1 = 1; float4 ShadowCasterMult_2 = 1; - if (((_Udon_ShadowMapIndex[LightCounter] > 0.5) && (_Udon_ShadowMapIndex[LightCounter] < 1.5) && (_EnableShadowCasting > 0.5)) || (_Udon_ShadowMapIndex[LightCounter] > 2.5 && _EnableShadowCasting)) + if (shadowCastingEnabled) { - float4 sc1 = SampleShadowcasterPlaneWS_Basis( - _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, _BlurPixels, _Udon_shadowCasterTex_1_TexelSize.xy); - ShadowCasterMult_1 = max(sc1, _Udon_MinBrightnessShadow_1); - } - if (_Udon_ShadowMapIndex[LightCounter] > 1.5 && (_EnableShadowCasting > 0.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, _BlurPixels, _Udon_shadowCasterTex_2_TexelSize.xy); - ShadowCasterMult_2 = max(sc2, _Udon_MinBrightnessShadow_2); + half smIndex = _Udon_ShadowMapIndex[LightCounter]; + if ((smIndex > 0.5 && smIndex < 1.5) || smIndex > 2.5) + { + float4 sc1 = SampleShadowcasterPlaneWS_Basis( + _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, _BlurPixels, _Udon_shadowCasterTex_1_TexelSize.xy); + ShadowCasterMult_1 = max(sc1, _Udon_MinBrightnessShadow_1); + } + if (smIndex > 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, _BlurPixels, _Udon_shadowCasterTex_2_TexelSize.xy); + ShadowCasterMult_2 = max(sc2, _Udon_MinBrightnessShadow_2); + } } dmax = dmax + contrib * float4(LightColor, 1) * NdotL * ShadowCasterMult_1 * ShadowCasterMult_2; diff --git a/Shader/Standard_Lightmap_2SP.shader b/Shader/Standard_Lightmap_2SP.shader index 51048fe..f53dc26 100644 --- a/Shader/Standard_Lightmap_2SP.shader +++ b/Shader/Standard_Lightmap_2SP.shader @@ -190,21 +190,25 @@ Shader "DeMuenu/World/Hoppou/Standard_Lightmap_2SP" float4 ShadowCasterMult_1 = 1; float4 ShadowCasterMult_2 = 1; - if (((_Udon_ShadowMapIndex[LightCounter] > 0.5) && (_Udon_ShadowMapIndex[LightCounter] < 1.5) && (_EnableShadowCasting > 0.5)) || (_Udon_ShadowMapIndex[LightCounter] > 2.5 && _EnableShadowCasting)) + if (shadowCastingEnabled) { - float4 sc1 = SampleShadowcasterPlaneWS_Basis( - _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, _BlurPixels, _Udon_shadowCasterTex_1_TexelSize.xy); - ShadowCasterMult_1 = max(sc1, _Udon_MinBrightnessShadow_1); - } - if (_Udon_ShadowMapIndex[LightCounter] > 1.5 && (_EnableShadowCasting > 0.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, _BlurPixels, _Udon_shadowCasterTex_2_TexelSize.xy); - ShadowCasterMult_2 = max(sc2, _Udon_MinBrightnessShadow_2); + half smIndex = _Udon_ShadowMapIndex[LightCounter]; + if ((smIndex > 0.5 && smIndex < 1.5) || smIndex > 2.5) + { + float4 sc1 = SampleShadowcasterPlaneWS_Basis( + _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, _BlurPixels, _Udon_shadowCasterTex_1_TexelSize.xy); + ShadowCasterMult_1 = max(sc1, _Udon_MinBrightnessShadow_1); + } + if (smIndex > 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, _BlurPixels, _Udon_shadowCasterTex_2_TexelSize.xy); + ShadowCasterMult_2 = max(sc2, _Udon_MinBrightnessShadow_2); + } } dmax = dmax + contrib * float4(LightColor, 1) * NdotL * ShadowCasterMult_1 * ShadowCasterMult_2; diff --git a/Shader/Water_2SP.shader b/Shader/Water_2SP.shader index 7b70d35..ec2fda7 100644 --- a/Shader/Water_2SP.shader +++ b/Shader/Water_2SP.shader @@ -219,20 +219,25 @@ Shader "DeMuenu/World/Hoppou/WaterFlat_2SP" float4 ShadowCasterMult_1 = 1; float4 ShadowCasterMult_2 = 1; - if (((_Udon_ShadowMapIndex[LightCounter] > 0.5) && (_Udon_ShadowMapIndex[LightCounter] < 1.5) && (_EnableShadowCasting > 0.5)) || (_Udon_ShadowMapIndex[LightCounter] > 2.5 && _EnableShadowCasting)) + if (shadowCastingEnabled) { - float4 sc1 = SampleShadowcasterPlaneWS_Basis( - _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, _BlurPixels, _Udon_shadowCasterTex_1_TexelSize.xy); - ShadowCasterMult_1 = max(sc1, _Udon_MinBrightnessShadow_1); - } - if (_Udon_ShadowMapIndex[LightCounter] > 1.5 && (_EnableShadowCasting > 0.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, _BlurPixels, _Udon_shadowCasterTex_2_TexelSize.xy); - ShadowCasterMult_2 = max(sc2, _Udon_MinBrightnessShadow_2); + half smIndex = _Udon_ShadowMapIndex[LightCounter]; + if ((smIndex > 0.5 && smIndex < 1.5) || smIndex > 2.5) + { + float4 sc1 = SampleShadowcasterPlaneWS_Basis( + _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, _BlurPixels, _Udon_shadowCasterTex_1_TexelSize.xy); + ShadowCasterMult_1 = max(sc1, _Udon_MinBrightnessShadow_1); + } + if (smIndex > 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, _BlurPixels, _Udon_shadowCasterTex_2_TexelSize.xy); + ShadowCasterMult_2 = max(sc2, _Udon_MinBrightnessShadow_2); + } } //Watershader specific From 08866b359b4405ce9dc1d22e0dd55f9442e94427 Mon Sep 17 00:00:00 2001 From: DeMuenu <96650288+DeMuenu@users.noreply.github.com> Date: Tue, 24 Mar 2026 16:01:31 +0100 Subject: [PATCH 2/6] updated shader includes --- Shader/Includes/Moonlight.hlsl | 10 ++++++ Shader/Includes/Variables.hlsl | 50 ++++++++++++++++++++++------- Shader/LitParticles_2SP.shader | 35 +------------------- Shader/Standard_2SP.shader | 39 ++-------------------- Shader/Standard_Lightmap_2SP.shader | 41 ++--------------------- Shader/Water_2SP.shader | 39 ++-------------------- 6 files changed, 58 insertions(+), 156 deletions(-) create mode 100644 Shader/Includes/Moonlight.hlsl diff --git a/Shader/Includes/Moonlight.hlsl b/Shader/Includes/Moonlight.hlsl new file mode 100644 index 0000000..8f477d2 --- /dev/null +++ b/Shader/Includes/Moonlight.hlsl @@ -0,0 +1,10 @@ +#ifndef MOONLIGHT_CORE_INCLUDED +#define MOONLIGHT_CORE_INCLUDED + +#include "Variables.hlsl" +#include "DefaultSetup.hlsl" +#include "LightStrength.hlsl" +#include "Lambert.hlsl" +#include "Shadowcaster.cginc" + +#endif \ No newline at end of file diff --git a/Shader/Includes/Variables.hlsl b/Shader/Includes/Variables.hlsl index 95e74a8..31dfa89 100644 --- a/Shader/Includes/Variables.hlsl +++ b/Shader/Includes/Variables.hlsl @@ -1,14 +1,40 @@ -#ifndef MoonlightGlobalVariables -#define MoonlightGlobalVariables \ - \ - float _InverseSqareMultiplier; \ - float _LightCutoffDistance; \ - \ - float4 _Udon_LightPositions[MAX_LIGHTS]; /* xyz = position */ \ - float4 _Udon_LightColors[MAX_LIGHTS]; /* xyz = position */ \ - float4 _Udon_LightDirections[MAX_LIGHTS]; /* xyz = direction, w = cos(halfAngle) */ \ - float _Udon_LightType[MAX_LIGHTS]; /* 0 = sphere, 1 = cone */ \ - float _Udon_ShadowMapIndex[MAX_LIGHTS];\ - float _Udon_PlayerCount; /* set via SetFloat */ \ +#ifndef MOONLIGHT_GLOBAL_VARIABLES_INCLUDED +#define MOONLIGHT_GLOBAL_VARIABLES_INCLUDED + +float _InverseSqareMultiplier; +float _LightCutoffDistance; + +float4 _Udon_LightPositions[MAX_LIGHTS]; /* xyz = position */ +float4 _Udon_LightColors[MAX_LIGHTS]; /* xyz = position */ +float4 _Udon_LightDirections[MAX_LIGHTS]; /* xyz = direction, w = cos(halfAngle) */ +float _Udon_LightType[MAX_LIGHTS]; /* 0 = sphere, 1 = cone */ +float _Udon_ShadowMapIndex[MAX_LIGHTS]; +float _Udon_PlayerCount; /* set via SetFloat */ + +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; +float4 _Udon_shadowCasterColor_1; +float4 _Udon_OutSideColor_1; +float _Udon_MinBrightnessShadow_1; + +float4 _Udon_Plane_Origin_2; +float4 _Udon_Plane_Uinv_2; +float4 _Udon_Plane_Vinv_2; +float4 _Udon_Plane_Normal_2; + +sampler2D _Udon_shadowCasterTex_2; +float4 _Udon_shadowCasterColor_2; +float4 _Udon_OutSideColor_2; +float _Udon_MinBrightnessShadow_2; + +float _BlurPixels; +float4 _Udon_shadowCasterTex_1_TexelSize; // xy = 1/width, 1/height +float4 _Udon_shadowCasterTex_2_TexelSize; + +bool _EnableShadowCasting; #endif \ No newline at end of file diff --git a/Shader/LitParticles_2SP.shader b/Shader/LitParticles_2SP.shader index 03b0658..d0c9a46 100644 --- a/Shader/LitParticles_2SP.shader +++ b/Shader/LitParticles_2SP.shader @@ -35,11 +35,7 @@ Shader "DeMuenu/World/Hoppou/Particles/LitParticles_2SP" #define MAX_LIGHTS 80 // >= maxPlayers in script #include "UnityCG.cginc" - #include "Includes/LightStrength.hlsl" - #include "Includes/Lambert.hlsl" - #include "Includes/DefaultSetup.hlsl" - #include "Includes/Variables.hlsl" - #include "Includes/Shadowcaster.cginc" + #include "Includes/Moonlight.hlsl" @@ -79,35 +75,6 @@ Shader "DeMuenu/World/Hoppou/Particles/LitParticles_2SP" float4 _EmmissiveColor; float _EmmissiveStrength; - - MoonlightGlobalVariables - - 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; - float4 _Udon_shadowCasterColor_1; - float4 _Udon_OutSideColor_1; - float _Udon_MinBrightnessShadow_1; - - float4 _Udon_Plane_Origin_2; - float4 _Udon_Plane_Uinv_2; - float4 _Udon_Plane_Vinv_2; - float4 _Udon_Plane_Normal_2; - - sampler2D _Udon_shadowCasterTex_2; - float4 _Udon_shadowCasterColor_2; - float4 _Udon_OutSideColor_2; - float _Udon_MinBrightnessShadow_2; - - float _BlurPixels; - float4 _Udon_shadowCasterTex_1_TexelSize; // xy = 1/width, 1/height - float4 _Udon_shadowCasterTex_2_TexelSize; - - bool _EnableShadowCasting; - v2f vert (appdata v) { v2f o; diff --git a/Shader/Standard_2SP.shader b/Shader/Standard_2SP.shader index cbb91b1..25825b7 100644 --- a/Shader/Standard_2SP.shader +++ b/Shader/Standard_2SP.shader @@ -37,16 +37,12 @@ Shader "DeMuenu/World/Hoppou/Standard_2SP" #pragma vertex vert #pragma fragment frag - #include "UnityCG.cginc" - #include "Includes/LightStrength.hlsl" - #include "Includes/Lambert.hlsl" - #include "Includes/DefaultSetup.hlsl" - #include "Includes/Variables.hlsl" - #include "Includes/Shadowcaster.cginc" - //Moonlight Defines #define MAX_LIGHTS 80 // >= maxPlayers in script //Moonlight Defines END + + #include "UnityCG.cginc" + #include "Includes/Moonlight.hlsl" struct appdata { @@ -89,35 +85,6 @@ Shader "DeMuenu/World/Hoppou/Standard_2SP" float _EmmissiveStrength; - MoonlightGlobalVariables - - - 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; - float4 _Udon_shadowCasterColor_1; - float4 _Udon_OutSideColor_1; - float _Udon_MinBrightnessShadow_1; - - float4 _Udon_Plane_Origin_2; - float4 _Udon_Plane_Uinv_2; - float4 _Udon_Plane_Vinv_2; - float4 _Udon_Plane_Normal_2; - - sampler2D _Udon_shadowCasterTex_2; - float4 _Udon_shadowCasterColor_2; - float4 _Udon_OutSideColor_2; - float _Udon_MinBrightnessShadow_2; - - float _BlurPixels; - float4 _Udon_shadowCasterTex_1_TexelSize; // xy = 1/width, 1/height - float4 _Udon_shadowCasterTex_2_TexelSize; - - bool _EnableShadowCasting; - v2f vert (appdata v) { v2f o; diff --git a/Shader/Standard_Lightmap_2SP.shader b/Shader/Standard_Lightmap_2SP.shader index f53dc26..137255c 100644 --- a/Shader/Standard_Lightmap_2SP.shader +++ b/Shader/Standard_Lightmap_2SP.shader @@ -39,16 +39,12 @@ Shader "DeMuenu/World/Hoppou/Standard_Lightmap_2SP" #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile _ DIRLIGHTMAP_COMBINED - #include "UnityCG.cginc" - #include "Includes/LightStrength.hlsl" - #include "Includes/Lambert.hlsl" - #include "Includes/DefaultSetup.hlsl" - #include "Includes/Variables.hlsl" - #include "Includes/Shadowcaster.cginc" - //Moonlight Defines #define MAX_LIGHTS 80 // >= maxPlayers in script //Moonlight Defines END + + #include "UnityCG.cginc" + #include "Includes/Moonlight.hlsl" struct appdata { @@ -97,37 +93,6 @@ Shader "DeMuenu/World/Hoppou/Standard_Lightmap_2SP" float _EmmissiveStrength; - MoonlightGlobalVariables - - - 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; - float4 _Udon_shadowCasterColor_1; - float4 _Udon_OutSideColor_1; - float _Udon_MinBrightnessShadow_1; - - float4 _Udon_Plane_Origin_2; - float4 _Udon_Plane_Uinv_2; - float4 _Udon_Plane_Vinv_2; - float4 _Udon_Plane_Normal_2; - - sampler2D _Udon_shadowCasterTex_2; - float4 _Udon_shadowCasterColor_2; - float4 _Udon_OutSideColor_2; - float _Udon_MinBrightnessShadow_2; - - float _BlurPixels; - float4 _Udon_shadowCasterTex_1_TexelSize; // xy = 1/width, 1/height - float4 _Udon_shadowCasterTex_2_TexelSize; - - bool _EnableShadowCasting; - - - v2f vert (appdata v) { v2f o; diff --git a/Shader/Water_2SP.shader b/Shader/Water_2SP.shader index ec2fda7..53bf98c 100644 --- a/Shader/Water_2SP.shader +++ b/Shader/Water_2SP.shader @@ -49,16 +49,12 @@ Shader "DeMuenu/World/Hoppou/WaterFlat_2SP" #pragma vertex vert #pragma fragment frag - #include "UnityCG.cginc" - #include "Includes/LightStrength.hlsl" - #include "Includes/Lambert.hlsl" - #include "Includes/DefaultSetup.hlsl" - #include "Includes/Variables.hlsl" - #include "Includes/Shadowcaster.cginc" - //Moonlight Defines #define MAX_LIGHTS 80 // >= maxPlayers in script //Moonlight Defines END + + #include "UnityCG.cginc" + #include "Includes/Moonlight.hlsl" struct appdata { @@ -95,35 +91,6 @@ Shader "DeMuenu/World/Hoppou/WaterFlat_2SP" float _NormalMapScrollSpeed2; float _MinTransparency; - - MoonlightGlobalVariables - - 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; - float4 _Udon_shadowCasterColor_1; - float4 _Udon_OutSideColor_1; - float _Udon_MinBrightnessShadow_1; - - float4 _Udon_Plane_Origin_2; - float4 _Udon_Plane_Uinv_2; - float4 _Udon_Plane_Vinv_2; - float4 _Udon_Plane_Normal_2; - - sampler2D _Udon_shadowCasterTex_2; - float4 _Udon_shadowCasterColor_2; - float4 _Udon_OutSideColor_2; - float _Udon_MinBrightnessShadow_2; - - float _BlurPixels; - float4 _Udon_shadowCasterTex_1_TexelSize; // xy = 1/width, 1/height - float4 _Udon_shadowCasterTex_2_TexelSize; - - bool _EnableShadowCasting; - //Watershader specific float _SpecPower, _SpecIntensity; From 20034f061d6b9737ad4cf7615bf333f6452d0776 Mon Sep 17 00:00:00 2001 From: DeMuenu <96650288+DeMuenu@users.noreply.github.com> Date: Tue, 24 Mar 2026 16:16:34 +0100 Subject: [PATCH 3/6] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ba16da0..b745e65 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,13 @@ What this includes: - Point/spotlights editable at runtime. - A couple of premade shaders (standard, particle). - Premade code handling lights, normals and a Lambertian diffuse. +- Shadow caster planes Work in progress: - Water shader - Documentation - More performance testing/improvements -- Shadow caster planes + Planned: - Support for additive baked light maps and ambient lighting in the standard shader. @@ -36,9 +37,10 @@ On PC, I haven't encountered any frame drops in the editor at all, even with 400 2. Add the `LightUpdater` component to a GameObject in your scene: - Tweak strength/intensity of the local and remote player if you want them to have an attached light. + - Configure the `PlayerShadowMapIndex` if you want players to interact with shadows. 3. For lights, attach `LightdataStorage` to a Transform and configure: - - `range`, `type`, `color`, `intensity`, and `spotAngleDeg`. + - `range`, `lightType`, `color`, `intensity`, `spotAngleDeg`, and `shadowMapIndex`. 4. On your light's `LightdataStorage` component, assign your scene's `LightUpdater` to the `Light Updater` field. This allows lights to be added or removed dynamically at runtime. From a3f95883bed5cbaf63a8b7b809a38cdcb31bf975 Mon Sep 17 00:00:00 2001 From: DeMuenu <96650288+DeMuenu@users.noreply.github.com> Date: Tue, 24 Mar 2026 17:29:21 +0100 Subject: [PATCH 4/6] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b745e65..c1414cd 100644 --- a/README.md +++ b/README.md @@ -64,4 +64,4 @@ On PC, I haven't encountered any frame drops in the editor at all, even with 400 ## Contributing If you want to help with development, please contact me on Discord (@demuenu) so we can coordinate our efforts. -If your somebody with a education in Computer graphics, I would be even more thankfull for your help. As right now, it's just me with ~1.5 years of messing around in Shaderlab and ChatGPT as my advisor. So I'm sure that there are serious flaws in the codebase :-) +If your somebody with a education in Computer graphics, I would be even more thankful for your help. As right now, it's just me with ~1.5 years of messing around in Shaderlab and ChatGPT as my advisor. So I'm sure that there are serious flaws in the codebase :-) From 79ad33c5f3df4a608191e015fb0cd06d5ccf2c14 Mon Sep 17 00:00:00 2001 From: DeMuenu <96650288+DeMuenu@users.noreply.github.com> Date: Thu, 26 Mar 2026 23:01:38 +0100 Subject: [PATCH 5/6] Fix Gemini stuff --- EditorPreview/Editor/LightupdaterPreview.cs | 2 +- EditorPreview/LightUpdater.Editor.cs | 2 +- Scripts/LightUpdater.cs | 8 +++----- Shader/Includes/Moonlight.hlsl.meta | 7 +++++++ 4 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 Shader/Includes/Moonlight.hlsl.meta diff --git a/EditorPreview/Editor/LightupdaterPreview.cs b/EditorPreview/Editor/LightupdaterPreview.cs index e24f677..f0ead61 100644 --- a/EditorPreview/Editor/LightupdaterPreview.cs +++ b/EditorPreview/Editor/LightupdaterPreview.cs @@ -85,7 +85,7 @@ public static class LightUpdaterPreview static void PushFromBehaviour(LightUpdater src) { - int max = Mathf.Max(1, src.maxLights); + int max = Mathf.Max(1, LightUpdater.maxLights); EnsureArrays(src, max); var c = _cache[src]; diff --git a/EditorPreview/LightUpdater.Editor.cs b/EditorPreview/LightUpdater.Editor.cs index 4e6a036..a151899 100644 --- a/EditorPreview/LightUpdater.Editor.cs +++ b/EditorPreview/LightUpdater.Editor.cs @@ -1,5 +1,5 @@ // Assets/Lighting/Scripts/LightUpdater.Editor.cs -#if UNITY_EDITOR +#if !COMPILER_UDONSHARP && UNITY_EDITOR using UnityEngine; public partial class LightUpdater diff --git a/Scripts/LightUpdater.cs b/Scripts/LightUpdater.cs index df0f2f7..4ab7796 100644 --- a/Scripts/LightUpdater.cs +++ b/Scripts/LightUpdater.cs @@ -47,9 +47,9 @@ public partial class LightUpdater : UdonSharpBehaviour [Tooltip("float array: shadow map index (0=none, 1-4=shadow map index)")] public string shadowMapIndexProperty = "_Udon_ShadowMapIndex"; - [Header("Max Lights (advanced users)")] + [Header("Max Lighetts (advanced users)")] [Tooltip("Hard cap / array size. 80 = default cap")] - public int maxLights = 80; + public const int maxLights = 80; @@ -66,7 +66,7 @@ public partial class LightUpdater : UdonSharpBehaviour private float[] _ShadowMapArray; private bool _ShadowMap_isDirty = false; - private LightdataStorage[] _sceneLights; + private LightdataStorage[] _sceneLights = new LightdataStorage[maxLights]; private int _sceneLightCount = 0; private VRCPlayerApi[] _players; @@ -85,14 +85,12 @@ public partial class LightUpdater : UdonSharpBehaviour void Start() { - if (maxLights < 1) maxLights = 1; _positions = new Vector4[maxLights]; _lightColors = new Vector4[maxLights]; _directions = new Vector4[maxLights]; _TypeArray = new float[maxLights]; _ShadowMapArray = new float[maxLights]; - _sceneLights = new LightdataStorage[maxLights]; _players = new VRCPlayerApi[maxLights]; diff --git a/Shader/Includes/Moonlight.hlsl.meta b/Shader/Includes/Moonlight.hlsl.meta new file mode 100644 index 0000000..c566c5a --- /dev/null +++ b/Shader/Includes/Moonlight.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1193ddffee5ac344ea57d621ec8150f6 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 1a30f720109acf248bbf44c737bb466a3dbbd88a Mon Sep 17 00:00:00 2001 From: DeMuenu <96650288+DeMuenu@users.noreply.github.com> Date: Sat, 28 Mar 2026 17:15:19 +0100 Subject: [PATCH 6/6] optimisations skipping empty for loops --- Scripts/LightUpdater.cs | 2 +- Shader/Includes/LightStrength.hlsl | 3 ++- Shader/LitParticles_2SP.shader | 2 +- Shader/Standard_2SP.shader | 2 +- Shader/Standard_Lightmap_2SP.shader | 2 +- Shader/Water_2SP.shader | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Scripts/LightUpdater.cs b/Scripts/LightUpdater.cs index 4ab7796..dedffc7 100644 --- a/Scripts/LightUpdater.cs +++ b/Scripts/LightUpdater.cs @@ -368,7 +368,7 @@ public partial class LightUpdater : UdonSharpBehaviour if (pushShadowMap) VRCShader.SetGlobalFloatArray(UdonID_ShadowMapIndex, _ShadowMapArray); VRCShader.SetGlobalFloat(UdonID_LightCount, currentCount); - Debug.Log($"[MoonlightVRC] Pushed {currentCount} lights to shader."); + //Debug.Log($"[MoonlightVRC] Pushed {currentCount} lights to shader."); // Only now mark them clean if (pushPositions) { _positons_isDirty = false; } diff --git a/Shader/Includes/LightStrength.hlsl b/Shader/Includes/LightStrength.hlsl index 28dcfcb..adc4c57 100644 --- a/Shader/Includes/LightStrength.hlsl +++ b/Shader/Includes/LightStrength.hlsl @@ -6,7 +6,7 @@ { \ float distAtten = max(1.0, distanceFromLight - radius) * invSqMul; \ contrib = _Udon_LightColors[LightCounter].a / max(1e-4, distAtten * distAtten); \ - \ + if (contrib == 0.0) continue;\ dIntensity += contrib; \ } \ else if (typeId == 1) \ @@ -18,6 +18,7 @@ contrib = smoothstep(radius,_Udon_LightDirections[LightCounter].w, contrib); \ \ contrib = contrib * invSq; \ + if (contrib == 0.0) continue;\ dIntensity += contrib; \ } \ half3 LightColor = _Udon_LightColors[LightCounter].xyz; \ diff --git a/Shader/LitParticles_2SP.shader b/Shader/LitParticles_2SP.shader index d0c9a46..6365b79 100644 --- a/Shader/LitParticles_2SP.shader +++ b/Shader/LitParticles_2SP.shader @@ -105,7 +105,7 @@ Shader "DeMuenu/World/Hoppou/Particles/LitParticles_2SP" OutLoopSetup(i, _Udon_PlayerCount) //defines count, N, dmax, dIntensity [loop] - for (int LightCounter = 0; LightCounter < MAX_LIGHTS; LightCounter++) + for (int LightCounter = 0; LightCounter < count; LightCounter++) { InLoopSetup(_Udon_LightPositions, LightCounter, count, i); //defines distanceFromLight, contrib diff --git a/Shader/Standard_2SP.shader b/Shader/Standard_2SP.shader index 25825b7..7945607 100644 --- a/Shader/Standard_2SP.shader +++ b/Shader/Standard_2SP.shader @@ -130,7 +130,7 @@ Shader "DeMuenu/World/Hoppou/Standard_2SP" OutLoopSetup(i, _Udon_PlayerCount) //defines count, N, dmax, dIntensity [loop] - for (int LightCounter = 0; LightCounter < MAX_LIGHTS; LightCounter++) + for (int LightCounter = 0; LightCounter < count; LightCounter++) { InLoopSetup(_Udon_LightPositions, LightCounter, count, i); //defines distanceFromLight, contrib diff --git a/Shader/Standard_Lightmap_2SP.shader b/Shader/Standard_Lightmap_2SP.shader index 137255c..c13071c 100644 --- a/Shader/Standard_Lightmap_2SP.shader +++ b/Shader/Standard_Lightmap_2SP.shader @@ -142,7 +142,7 @@ Shader "DeMuenu/World/Hoppou/Standard_Lightmap_2SP" OutLoopSetup(i, _Udon_PlayerCount) //defines count, N, dmax, dIntensity [loop] - for (int LightCounter = 0; LightCounter < MAX_LIGHTS; LightCounter++) + for (int LightCounter = 0; LightCounter < count; LightCounter++) { InLoopSetup(_Udon_LightPositions, LightCounter, count, i); //defines distanceFromLight, contrib diff --git a/Shader/Water_2SP.shader b/Shader/Water_2SP.shader index 53bf98c..c38fc8b 100644 --- a/Shader/Water_2SP.shader +++ b/Shader/Water_2SP.shader @@ -175,7 +175,7 @@ Shader "DeMuenu/World/Hoppou/WaterFlat_2SP" OutLoopSetup(i, _Udon_PlayerCount) //defines count, N, dmax, dIntensity [loop] - for (int LightCounter = 0; LightCounter < MAX_LIGHTS; LightCounter++) + for (int LightCounter = 0; LightCounter < count; LightCounter++) { InLoopSetup(_Udon_LightPositions, LightCounter, count, i); //defines distanceFromLight, contrib