red-sim-light-volumesudon/VRCLightVolumes/LightVolumeSetup.cs
2025-09-17 01:38:27 +01:00

335 lines
No EOL
12 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
namespace VRCLightVolumes
{
[ExecuteAlways]
public class LightVolumeSetup : MonoBehaviour
{
[SerializeField]
public List<LightVolume> LightVolumes = new List<LightVolume>();
[SerializeField]
public List<float> LightVolumesWeights = new List<float>();
[SerializeField]
public List<PointLightVolume> PointLightVolumes = new List<PointLightVolume>();
[Header("Point Light Volumes")]
public LightVolumeSetup.TextureArrayResolution Resolution = LightVolumeSetup.TextureArrayResolution._128x128;
public LightVolumeSetup.TextureArrayFormat Format = LightVolumeSetup.TextureArrayFormat.RGBAHalf;
[Range(0.05f, 1f)]
[Tooltip("The minimum brightness at a point due to lighting from a Point Light Volume, before the light is culled. Larger values will result in better performance, but light attenuation will be less physically correct.")]
public float LightsBrightnessCutoff = 0.35f;
[Header("Baking")]
[Tooltip("Bakery usually gives better results and works faster.")]
public LightVolumeSetup.Baking BakingMode = LightVolumeSetup.Baking.Progressive;
[Tooltip("Removes baked noise in Light Volumes but may slightly reduce sharpness. Recommended to keep it enabled.")]
public bool Denoise = true;
[Tooltip("Whether to dilate valid probe data into invalid probes, such as probes that are inside geometry. Helps mitigate light leaking.")]
public bool DilateInvalidProbes = true;
[Range(1f, 8f)]
[Tooltip("How many iterations to run dilation for. Higher values will result in less leaking, but will also cause longer bakes.")]
public int DilationIterations = 1;
[Range(0f, 1f)]
[Tooltip("The percentage of rays shot from a probe that should hit backfaces before the probe is considered invalid for the purpose of dilation. 0 means every probe is invalid, 1 means every probe is valid.")]
public float DilationBackfaceBias = 0.1f;
[Tooltip("Automatically fixes Bakery's \"burned\" light probes after a scene bake. But decreases their contrast slightly.")]
public bool FixLightProbesL1 = true;
[Header("Visuals")]
[Tooltip("When enabled, areas outside Light Volumes fall back to light probes. Otherwise, the Light Volume with the smallest weight is used as fallback. It also improves performance.")]
public bool LightProbesBlending = true;
[Tooltip("Disables smooth blending with areas outside Light Volumes. Use it if your entire scene's play area is covered by Light Volumes. It also improves performance.")]
public bool SharpBounds = true;
[Tooltip("Automatically updates most of the volumes properties in runtime. Enabling/Disabling, Color and Intensity updates automatically even without this option enabled. Position, Rotation and Scale gets updated only for volumes that are marked dynamic.")]
public bool AutoUpdateVolumes = false;
[Min(1f)]
[Tooltip("Limits the maximum number of additive volumes and point light volumes that can affect a single pixel. If you have many dynamic additive or point light volumes that may overlap, it's good practice to limit overdraw to maintain performance.")]
public int AdditiveMaxOverdraw = 4;
[Header("Debug")]
[Tooltip("Removes all Light Volume scripts in play mode, except Udon components. Useful for testing in a clean setup, just like in VRChat. For example, Auto Update Volumes and Dynamic Light Volumes will work just like in VRChat.")]
public bool DestroyInPlayMode = false;
[SerializeField]
public List<LightVolumeData> LightVolumeDataList = new List<LightVolumeData>();
public VRCLightVolumes.LightVolumeManager LightVolumeManager;
private bool _dontSync = true;
public LightVolumeSetup.Baking _bakingModePrev;
public bool IsLegacyUVWConverted = false;
private LightVolumeSetup.TextureArrayResolution _resolutionPrev = LightVolumeSetup.TextureArrayResolution._128x128;
private LightVolumeSetup.TextureArrayFormat _formatPrev = LightVolumeSetup.TextureArrayFormat.RGBAHalf;
public bool DontSync
{
get
{
return (Application.get_isPlaying() ? this._dontSync : false);
}
set
{
this._dontSync = value;
}
}
public bool IsBakeryMode
{
get
{
return this.BakingMode == LightVolumeSetup.Baking.Bakery;
}
}
public LightVolumeSetup()
{
}
public void BakeOcclusionVolumes()
{
}
[RuntimeInitializeOnLoadMethod(,)] // JustDecompile was unable to locate the assembly where attribute parameters types are defined. Generating parameters values is impossible.
private static void CommitSudoku()
{
if (Application.get_isPlaying())
{
bool flag = false;
LightVolumeSetup[] lightVolumeSetupArray = UnityEngine.Object.FindObjectsByType<LightVolumeSetup>(1, 0);
for (int i = 0; i < (int)lightVolumeSetupArray.Length; i++)
{
if (lightVolumeSetupArray[i].DestroyInPlayMode)
{
flag = true;
}
else
{
lightVolumeSetupArray[i].DontSync = false;
}
}
if (flag)
{
LightVolume[] lightVolumeArray = UnityEngine.Object.FindObjectsByType<LightVolume>(1, 0);
for (int j = 0; j < (int)lightVolumeArray.Length; j++)
{
UnityEngine.Object.Destroy(lightVolumeArray[j]);
}
PointLightVolume[] pointLightVolumeArray = UnityEngine.Object.FindObjectsByType<PointLightVolume>(1, 0);
for (int k = 0; k < (int)pointLightVolumeArray.Length; k++)
{
UnityEngine.Object.Destroy(pointLightVolumeArray[k]);
}
for (int l = 0; l < (int)lightVolumeSetupArray.Length; l++)
{
UnityEngine.Object.Destroy(lightVolumeSetupArray[l]);
}
}
}
}
private PointLightVolumeInstance[] GetPointLightVolumeInstances()
{
List<PointLightVolumeInstance> pointLightVolumeInstances = new List<PointLightVolumeInstance>();
int count = this.PointLightVolumes.Count;
for (int i = 0; i < count; i++)
{
if ((this.PointLightVolumes[i] == null ? false : this.PointLightVolumes[i].PointLightVolumeInstance != null))
{
pointLightVolumeInstances.Add(this.PointLightVolumes[i].PointLightVolumeInstance);
}
}
return pointLightVolumeInstances.ToArray();
}
public void RefreshVolumesList()
{
if (!this.DontSync)
{
LightVolume[] lightVolumeArray = UnityEngine.Object.FindObjectsOfType<LightVolume>(true);
for (int i = 0; i < (int)lightVolumeArray.Length; i++)
{
if (!lightVolumeArray[i].CompareTag("EditorOnly"))
{
if (!this.LightVolumes.Contains(lightVolumeArray[i]))
{
this.LightVolumes.Add(lightVolumeArray[i]);
this.LightVolumesWeights.Add(0f);
}
}
}
for (int j = 0; j < this.LightVolumes.Count; j++)
{
if ((this.LightVolumes[j] == null ? true : this.LightVolumes[j].CompareTag("EditorOnly")))
{
this.LightVolumes.RemoveAt(j);
this.LightVolumesWeights.RemoveAt(j);
j--;
}
}
PointLightVolume[] pointLightVolumeArray = UnityEngine.Object.FindObjectsOfType<PointLightVolume>(true);
for (int k = 0; k < (int)pointLightVolumeArray.Length; k++)
{
if (!pointLightVolumeArray[k].CompareTag("EditorOnly"))
{
if (!this.PointLightVolumes.Contains(pointLightVolumeArray[k]))
{
this.PointLightVolumes.Add(pointLightVolumeArray[k]);
}
}
}
for (int l = 0; l < this.PointLightVolumes.Count; l++)
{
if ((this.PointLightVolumes[l] == null ? true : this.PointLightVolumes[l].CompareTag("EditorOnly")))
{
this.PointLightVolumes.RemoveAt(l);
l--;
}
}
this.SyncUdonScript();
}
}
public void RegisterPostProcessorCRT(CustomRenderTexture crt)
{
if ((crt == null ? false : Array.IndexOf<CustomRenderTexture>(this.LightVolumeManager.AtlasPostProcessors, crt) == -1))
{
VRCLightVolumes.LightVolumeManager lightVolumeManager = this.LightVolumeManager;
if (lightVolumeManager.AtlasPostProcessors == null)
{
lightVolumeManager.AtlasPostProcessors = new CustomRenderTexture[0];
}
Array.Resize<CustomRenderTexture>(ref this.LightVolumeManager.AtlasPostProcessors, (int)this.LightVolumeManager.AtlasPostProcessors.Length + 1);
CustomRenderTexture[] atlasPostProcessors = this.LightVolumeManager.AtlasPostProcessors;
atlasPostProcessors[(int)atlasPostProcessors.Length - 1] = crt;
Debug.Log(String.Concat("[LightVolumeSetup] Registered post processor CRT: ", crt.get_name()));
this.UpdatePostProcessors();
}
}
public void SyncUdonScript()
{
if ((this.LightVolumeManager == null ? false : !this.DontSync))
{
this.LightVolumeManager.AutoUpdateVolumes = this.AutoUpdateVolumes;
this.LightVolumeManager.LightProbesBlending = this.LightProbesBlending;
this.LightVolumeManager.SharpBounds = this.SharpBounds;
this.LightVolumeManager.AdditiveMaxOverdraw = this.AdditiveMaxOverdraw;
this.LightVolumeManager.LightsBrightnessCutoff = this.LightsBrightnessCutoff;
if (this.LightVolumes.Count != 0)
{
this.LightVolumeManager.LightVolumeInstances = LightVolumeDataSorter.GetData(LightVolumeDataSorter.SortData(this.LightVolumeDataList));
}
if (this.PointLightVolumes.Count != 0)
{
this.LightVolumeManager.PointLightVolumeInstances = this.GetPointLightVolumeInstances();
}
this.LightVolumeManager.UpdateVolumes();
}
}
public void UnregisterPostProcessorCRT(CustomRenderTexture crt)
{
if (crt != null)
{
int num = Array.IndexOf<CustomRenderTexture>(this.LightVolumeManager.AtlasPostProcessors, crt);
if (num >= 0)
{
CustomRenderTexture[] atlasPostProcessors = new CustomRenderTexture[(int)this.LightVolumeManager.AtlasPostProcessors.Length - 1];
int num1 = 0;
int num2 = 0;
while (num1 < (int)this.LightVolumeManager.AtlasPostProcessors.Length)
{
if (num1 != num)
{
int num3 = num2;
num2 = num3 + 1;
atlasPostProcessors[num3] = this.LightVolumeManager.AtlasPostProcessors[num1];
}
num1++;
}
this.LightVolumeManager.AtlasPostProcessors = atlasPostProcessors;
Debug.Log(String.Concat("[LightVolumeSetup] Unregistered post processor CRT: ", crt.get_name()));
this.UpdatePostProcessors();
}
}
}
private void UpdatePostProcessors()
{
if ((this.LightVolumeManager.AtlasPostProcessors == null ? false : this.LightVolumeManager.AtlasPostProcessors.Length != 0))
{
Texture3D lightVolumeAtlasBase = this.LightVolumeManager.LightVolumeAtlasBase;
Texture texture = lightVolumeAtlasBase;
CustomRenderTexture[] atlasPostProcessors = this.LightVolumeManager.AtlasPostProcessors;
for (int i = 0; i < (int)atlasPostProcessors.Length; i++)
{
CustomRenderTexture customRenderTexture = atlasPostProcessors[i];
if (customRenderTexture != null)
{
customRenderTexture.Release();
customRenderTexture.set_dimension(3);
customRenderTexture.set_graphicsFormat(48);
customRenderTexture.set_updateMode(1);
if (lightVolumeAtlasBase != null)
{
customRenderTexture.set_width(lightVolumeAtlasBase.get_width());
customRenderTexture.set_height(lightVolumeAtlasBase.get_height());
customRenderTexture.set_volumeDepth(lightVolumeAtlasBase.get_depth());
}
customRenderTexture.get_material().set_mainTexture(texture);
texture = customRenderTexture;
this.LightVolumeManager.LightVolumeAtlas = customRenderTexture;
customRenderTexture.Update();
}
}
}
else
{
this.LightVolumeManager.LightVolumeAtlas = this.LightVolumeManager.LightVolumeAtlasBase;
}
}
public enum Baking
{
Progressive,
Bakery
}
public enum TextureArrayFormat
{
RGBA32 = 4,
RGBAHalf = 17,
RGBAFloat = 20
}
public enum TextureArrayResolution
{
_16x16 = 16,
_32x32 = 32,
_64x64 = 64,
_128x128 = 128,
_256x256 = 256,
_512x512 = 512,
_1024x1024 = 1024,
_2048x2048 = 2048
}
}
}