335 lines
No EOL
12 KiB
C#
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
|
|
}
|
|
}
|
|
} |