stolen code :D
This commit is contained in:
commit
cd9ea221d2
16 changed files with 2364 additions and 0 deletions
21
Properties/AssemblyInfo.cs
Normal file
21
Properties/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using MelonLoader;
|
||||
using red.sim.LightVolumesUdon;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security.Permissions;
|
||||
|
||||
[assembly: AssemblyVersion("0.0.0.0")]
|
||||
[assembly: CompilationRelaxations(8)]
|
||||
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
|
||||
[assembly: HarmonyDontPatchAll]
|
||||
[assembly: MelonAuthorColor(0xff, 40, 144, 209)]
|
||||
[assembly: MelonColor(0xff, 3, 252, 78)]
|
||||
[assembly: MelonGame("Alpha Blend Interactive", "ChilloutVR")]
|
||||
[assembly: MelonInfo(typeof(Main), "LightVolumesUdon", "1.0.0", "REDSIM , SketchFoxsky", "N/A")]
|
||||
[assembly: MelonPlatform(,)] // JustDecompile was unable to locate the assembly where attribute parameters types are defined. Generating parameters values is impossible.
|
||||
[assembly: MelonPlatformDomain(,)] // JustDecompile was unable to locate the assembly where attribute parameters types are defined. Generating parameters values is impossible.
|
||||
[assembly: RuntimeCompatibility(WrapNonExceptionThrows=true)]
|
||||
[assembly: SecurityPermission(, SkipVerification=true)]
|
||||
[module: RefSafetyRules(11)]
|
251
VRCLightVolumes/LVUtils.cs
Normal file
251
VRCLightVolumes/LVUtils.cs
Normal file
|
@ -0,0 +1,251 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace VRCLightVolumes
|
||||
{
|
||||
public class LVUtils
|
||||
{
|
||||
public LVUtils()
|
||||
{
|
||||
}
|
||||
|
||||
public static bool Apply3DTextureData(Texture3D texture, Color[] colors)
|
||||
{
|
||||
bool flag;
|
||||
try
|
||||
{
|
||||
texture.SetPixels(colors);
|
||||
texture.Apply(false);
|
||||
flag = true;
|
||||
}
|
||||
catch (UnityException unityException)
|
||||
{
|
||||
Debug.LogError(String.Concat("[LightVolumeUtils] Failed to SetPixels in the Texture3D. Error: ", unityException.Message));
|
||||
flag = false;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public static Vector3[] BilateralDenoise3D(Vector3[] input, int w, int h, int d, float sigmaSpatial = 1f, float sigmaRange = 0.1f)
|
||||
{
|
||||
Vector3[] vector3Array = new Vector3[(int)input.Length];
|
||||
int num = Mathf.CeilToInt(2f * sigmaSpatial);
|
||||
for (int i = 0; i < d; i++)
|
||||
{
|
||||
for (int j = 0; j < h; j++)
|
||||
{
|
||||
for (int k = 0; k < w; k++)
|
||||
{
|
||||
int num1 = k + j * w + i * w * h;
|
||||
Vector3 vector3 = input[num1];
|
||||
Vector3 _zero = Vector3.get_zero();
|
||||
float single = 0f;
|
||||
for (int l = -num; l <= num; l++)
|
||||
{
|
||||
for (int m = -num; m <= num; m++)
|
||||
{
|
||||
for (int n = -num; n <= num; n++)
|
||||
{
|
||||
int num2 = k + n;
|
||||
int num3 = j + m;
|
||||
int num4 = i + l;
|
||||
if ((num2 < 0 || num3 < 0 || num4 < 0 || num2 >= w || num3 >= h ? false : num4 < d))
|
||||
{
|
||||
int num5 = num2 + num3 * w + num4 * w * h;
|
||||
Vector3 vector31 = input[num5];
|
||||
float single1 = (float)(n * n + m * m + l * l);
|
||||
float _sqrMagnitude = (vector31 - vector3).get_sqrMagnitude();
|
||||
float single2 = Mathf.Exp(-single1 / (2f * sigmaSpatial * sigmaSpatial));
|
||||
float single3 = Mathf.Exp(-_sqrMagnitude / (2f * sigmaRange * sigmaRange));
|
||||
float single4 = single2 * single3;
|
||||
_zero = _zero + (vector31 * single4);
|
||||
single += single4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
vector3Array[num1] = (single > 0f ? _zero / single : vector3);
|
||||
}
|
||||
}
|
||||
}
|
||||
return vector3Array;
|
||||
}
|
||||
|
||||
public static Bounds BoundsFromTRS(Matrix4x4 trs)
|
||||
{
|
||||
Vector3 column = trs.GetColumn(3);
|
||||
Vector3 vector3 = trs.GetColumn(0) * 0.5f;
|
||||
Vector3 column1 = trs.GetColumn(1) * 0.5f;
|
||||
Vector3 vector31 = trs.GetColumn(2) * 0.5f;
|
||||
Vector3 vector32 = new Vector3(Mathf.Abs(vector3.x) + Mathf.Abs(column1.x) + Mathf.Abs(vector31.x), Mathf.Abs(vector3.y) + Mathf.Abs(column1.y) + Mathf.Abs(vector31.y), Mathf.Abs(vector3.z) + Mathf.Abs(column1.z) + Mathf.Abs(vector31.z));
|
||||
return new Bounds(column, vector32 * 2f);
|
||||
}
|
||||
|
||||
public static bool CheckSHL2(SphericalHarmonicsL2 sh)
|
||||
{
|
||||
bool flag;
|
||||
int num = 0;
|
||||
while (true)
|
||||
{
|
||||
if (num < 3)
|
||||
{
|
||||
int num1 = 4;
|
||||
while (num1 < 9)
|
||||
{
|
||||
if (sh.get_Item(num, num1) == 0f)
|
||||
{
|
||||
num1++;
|
||||
}
|
||||
else
|
||||
{
|
||||
flag = true;
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
num++;
|
||||
}
|
||||
else
|
||||
{
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public static SphericalHarmonicsL2 DeringSH(SphericalHarmonicsL2 sh)
|
||||
{
|
||||
Vector3 vector3 = new Vector3(sh.get_Item(0, 0), sh.get_Item(1, 0), sh.get_Item(2, 0));
|
||||
Vector3 vector31 = new Vector3(sh.get_Item(0, 3), sh.get_Item(0, 1), sh.get_Item(0, 2));
|
||||
Vector3 vector32 = new Vector3(sh.get_Item(1, 3), sh.get_Item(1, 1), sh.get_Item(1, 2));
|
||||
Vector3 vector33 = new Vector3(sh.get_Item(2, 3), sh.get_Item(2, 1), sh.get_Item(2, 2));
|
||||
vector31 = LVUtils.DeringSingleSH(vector3.x, vector31);
|
||||
vector32 = LVUtils.DeringSingleSH(vector3.y, vector32);
|
||||
vector33 = LVUtils.DeringSingleSH(vector3.z, vector33);
|
||||
sh.set_Item(0, 3, vector31.x);
|
||||
sh.set_Item(0, 1, vector31.y);
|
||||
sh.set_Item(0, 2, vector31.z);
|
||||
sh.set_Item(1, 3, vector32.x);
|
||||
sh.set_Item(1, 1, vector32.y);
|
||||
sh.set_Item(1, 2, vector32.z);
|
||||
sh.set_Item(2, 3, vector33.x);
|
||||
sh.set_Item(2, 1, vector33.y);
|
||||
sh.set_Item(2, 2, vector33.z);
|
||||
return sh;
|
||||
}
|
||||
|
||||
public static Vector3 DeringSingleSH(float L0, Vector3 L1)
|
||||
{
|
||||
L1 *= 0.5f;
|
||||
float _magnitude = L1.get_magnitude();
|
||||
if (((double)_magnitude <= 0 ? false : (double)L0 > 0))
|
||||
{
|
||||
L1 *= Mathf.Min(L0 / _magnitude, 1.13f);
|
||||
}
|
||||
return L1;
|
||||
}
|
||||
|
||||
public static Mesh GenerateIcoSphere(float radius = 0.5f, int subdivisions = 2)
|
||||
{
|
||||
LVUtils.u003cu003ec__DisplayClass12_0 vector3s = new LVUtils.u003cu003ec__DisplayClass12_0();
|
||||
Vector3[] vector3 = new Vector3[] { new Vector3(-0.5257311f, 0.8506508f, 0f), new Vector3(0.5257311f, 0.8506508f, 0f), new Vector3(-0.5257311f, -0.8506508f, 0f), new Vector3(0.5257311f, -0.8506508f, 0f), new Vector3(0f, -0.5257311f, 0.8506508f), new Vector3(0f, 0.5257311f, 0.8506508f), new Vector3(0f, -0.5257311f, -0.8506508f), new Vector3(0f, 0.5257311f, -0.8506508f), new Vector3(0.8506508f, 0f, -0.5257311f), new Vector3(0.8506508f, 0f, 0.5257311f), new Vector3(-0.8506508f, 0f, -0.5257311f), new Vector3(-0.8506508f, 0f, 0.5257311f) };
|
||||
int[] numArray = new Int32[] { 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 };
|
||||
vector3s.verts = new List<Vector3>(vector3);
|
||||
List<int> nums = new List<int>(numArray);
|
||||
vector3s.cache = new Dictionary<long, int>();
|
||||
subdivisions = Mathf.Clamp(subdivisions, 0, 8);
|
||||
for (int i = 0; i < subdivisions; i++)
|
||||
{
|
||||
vector3s.cache.Clear();
|
||||
List<int> nums1 = new List<int>(nums.Count * 4);
|
||||
for (int j = 0; j < nums.Count; j += 3)
|
||||
{
|
||||
int item = nums[j];
|
||||
int num = nums[j + 1];
|
||||
int item1 = nums[j + 2];
|
||||
int num1 = LVUtils.u003cGenerateIcoSphereu003eg__Midpointu007c12_0(item, num, ref vector3s);
|
||||
int num2 = LVUtils.u003cGenerateIcoSphereu003eg__Midpointu007c12_0(num, item1, ref vector3s);
|
||||
int num3 = LVUtils.u003cGenerateIcoSphereu003eg__Midpointu007c12_0(item1, item, ref vector3s);
|
||||
nums1.AddRange((IEnumerable<!0>)(new Int32[] { item, num1, num3, num, num2, num1, item1, num3, num2, num1, num2, num3 }));
|
||||
}
|
||||
nums = nums1;
|
||||
}
|
||||
for (int k = 0; k < vector3s.verts.Count; k++)
|
||||
{
|
||||
List<Vector3> vector3s1 = vector3s.verts;
|
||||
Vector3 vector31 = vector3s.verts[k];
|
||||
vector3s1[k] = vector31.get_normalized() * radius;
|
||||
}
|
||||
Mesh mesh = new Mesh();
|
||||
mesh.set_name(String.Format("IcoSphere_{0}", subdivisions));
|
||||
Mesh mesh1 = mesh;
|
||||
mesh1.SetVertices(vector3s.verts);
|
||||
mesh1.SetTriangles(nums, 0);
|
||||
mesh1.RecalculateNormals();
|
||||
mesh1.RecalculateBounds();
|
||||
return mesh1;
|
||||
}
|
||||
|
||||
public static Vector3[] GetPlaneVertices(Vector3 center, Quaternion rotation, float size)
|
||||
{
|
||||
Vector3 vector3 = (rotation * Vector3.get_right()) * size;
|
||||
Vector3 vector31 = (rotation * Vector3.get_up()) * size;
|
||||
return new Vector3[] { (center - vector3) - vector31, (center - vector3) + vector31, (center + vector3) + vector31, (center + vector3) - vector31 };
|
||||
}
|
||||
|
||||
public static bool IsInPrefabAsset(object obj)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void MarkDirty(object obj)
|
||||
{
|
||||
}
|
||||
|
||||
public static float Remap(float value, float MinOld, float MaxOld, float MinNew, float MaxNew)
|
||||
{
|
||||
float minNew = MinNew + (value - MinOld) * (MaxNew - MinNew) / (MaxOld - MinOld);
|
||||
return minNew;
|
||||
}
|
||||
|
||||
public static float RemapTo01(float value, float MinOld, float MaxOld)
|
||||
{
|
||||
return (value - MinOld) / (MaxOld - MinOld);
|
||||
}
|
||||
|
||||
public static void SaveAsAsset(object asset, string assetPath)
|
||||
{
|
||||
Debug.LogError("[LightVolumeUtils] You can only save asset in editor!");
|
||||
}
|
||||
|
||||
public static void SaveAsAssetDelayed(object asset, string assetPath, Action<bool> callback = null)
|
||||
{
|
||||
Debug.LogError("[LightVolumeUtils] You can only save asset in editor!");
|
||||
}
|
||||
|
||||
public static void SetLossyScale(Transform transform, Vector3 targetLossyScale, int maxIterations = 20)
|
||||
{
|
||||
Vector3 _localScale = transform.get_localScale();
|
||||
for (int i = 0; i < maxIterations; i++)
|
||||
{
|
||||
transform.set_localScale(_localScale);
|
||||
Vector3 _lossyScale = transform.get_lossyScale();
|
||||
Vector3 vector3 = new Vector3((_lossyScale.x != 0f ? targetLossyScale.x / _lossyScale.x : 1f), (_lossyScale.y != 0f ? targetLossyScale.y / _lossyScale.y : 1f), (_lossyScale.z != 0f ? targetLossyScale.z / _lossyScale.z : 1f));
|
||||
_localScale = new Vector3(_localScale.x * vector3.x, _localScale.y * vector3.y, _localScale.z * vector3.z);
|
||||
}
|
||||
}
|
||||
|
||||
public static void TextureSetReadWrite(Texture texture, bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
public static Vector3 TransformPoint(Vector3 point, Vector3 position, Quaternion rotation, Vector3 scale)
|
||||
{
|
||||
Vector3 vector3 = (rotation * Vector3.Scale(point, scale)) + position;
|
||||
return vector3;
|
||||
}
|
||||
}
|
||||
}
|
290
VRCLightVolumes/LightVolume.cs
Normal file
290
VRCLightVolumes/LightVolume.cs
Normal file
|
@ -0,0 +1,290 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRCLightVolumes
|
||||
{
|
||||
[ExecuteAlways]
|
||||
public class LightVolume : MonoBehaviour
|
||||
{
|
||||
[Header("Volume Setup")]
|
||||
[Tooltip("Defines whether this volume can be moved in runtime. Disabling this option slightly improves performance.")]
|
||||
public bool Dynamic;
|
||||
|
||||
[Tooltip("Additive volumes apply their light on top of others as an overlay. Useful for movable and togglable lights. They can also project light onto static lightmapped objects if the surface shader supports it.")]
|
||||
public bool Additive;
|
||||
|
||||
[ColorUsage(false)]
|
||||
[Tooltip("Multiplies the volume’s color by this value.")]
|
||||
public UnityEngine.Color Color = UnityEngine.Color.get_white();
|
||||
|
||||
[Tooltip("Brightness of the volume.")]
|
||||
public float Intensity = 1f;
|
||||
|
||||
[Range(0f, 1f)]
|
||||
[Tooltip("Size in meters of this Light Volume's overlapping regions for smooth blending with other volumes.")]
|
||||
public float SmoothBlending = 0.25f;
|
||||
|
||||
[Header("Baked Data")]
|
||||
[Tooltip("Texture3D with baked SH data required for future atlas packing. It won't be uploaded to VRChat. (L0r, L0g, L0b, L1r.z)")]
|
||||
public Texture3D Texture0;
|
||||
|
||||
[Tooltip("Texture3D with baked SH data required for future atlas packing. It won't be uploaded to VRChat. (L1r.x, L1g.x, L1b.x, L1g.z)")]
|
||||
public Texture3D Texture1;
|
||||
|
||||
[Tooltip("Texture3D with baked SH data required for future atlas packing. It won't be uploaded to VRChat. (L1r.y, L1g.y, L1b.y, L1b.z)")]
|
||||
public Texture3D Texture2;
|
||||
|
||||
[Tooltip("Optional Texture3D with baked shadow mask data for future atlas packing. It won't be uploaded to VRChat. Stores occlusion for up to 4 nearby point light volumes.")]
|
||||
public Texture3D ShadowsTexture;
|
||||
|
||||
[Header("Color Correction")]
|
||||
[Tooltip("Makes volume brighter or darker")]
|
||||
public float Exposure = 0f;
|
||||
|
||||
[Range(-1f, 1f)]
|
||||
[Tooltip("Makes dark volume colors brighter or darker.")]
|
||||
public float Shadows = 0f;
|
||||
|
||||
[Range(-1f, 1f)]
|
||||
[Tooltip("Makes bright volume colors brighter or darker.")]
|
||||
public float Highlights = 0f;
|
||||
|
||||
[Header("Baking Setup")]
|
||||
[Tooltip("Uncheck it if you don't want to rebake this volume's textures.")]
|
||||
public bool Bake = true;
|
||||
|
||||
[Tooltip("Uncheck it if you don't want to rebake occlusion data required for baked point light volumes shadows.")]
|
||||
public bool PointLightShadows = true;
|
||||
|
||||
[Tooltip("Shadow Mask will use the regular volume resolution multiplied by this value.")]
|
||||
public float ShadowsScale = 1f;
|
||||
|
||||
[Tooltip("Post-processes the baked occlusion texture with a softening blur. This can help mitigate 'blocky' shadows caused by aliasing, but also makes shadows less crispy.")]
|
||||
public bool BlurShadows = true;
|
||||
|
||||
[Tooltip("Automatically sets the resolution based on the Voxels Per Unit value.")]
|
||||
public bool AdaptiveResolution = true;
|
||||
|
||||
[Tooltip("Number of voxels used per meter, linearly. This value increases the Light Volume file size cubically.")]
|
||||
public float VoxelsPerUnit = 3f;
|
||||
|
||||
[Tooltip("Manual Light Volume resolution in voxel count.")]
|
||||
public Vector3Int Resolution = new Vector3Int(16, 16, 16);
|
||||
|
||||
public bool PreviewVoxels;
|
||||
|
||||
public VRCLightVolumes.LightVolumeInstance LightVolumeInstance;
|
||||
|
||||
public VRCLightVolumes.LightVolumeSetup LightVolumeSetup;
|
||||
|
||||
private Vector3[] _probesPositions = new Vector3[0];
|
||||
|
||||
private Vector3 _prevPos = Vector3.get_zero();
|
||||
|
||||
private Quaternion _prevRot = Quaternion.get_identity();
|
||||
|
||||
private Vector3 _prevScl = Vector3.get_one();
|
||||
|
||||
private float _prevExposure = 0f;
|
||||
|
||||
private float _prevShadows = 0f;
|
||||
|
||||
private float _prevHighlights = 0f;
|
||||
|
||||
private float _lastTimeColorCorrection = 0f;
|
||||
|
||||
private Material _previewMaterial;
|
||||
|
||||
private Mesh _previewMesh;
|
||||
|
||||
private ComputeBuffer _posBuf;
|
||||
|
||||
private ComputeBuffer _argsBuf;
|
||||
|
||||
private readonly static int _previewPosID;
|
||||
|
||||
private readonly static int _previewScaleID;
|
||||
|
||||
private bool _isValidated = false;
|
||||
|
||||
public Vector3Int OcclusionResolution
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Vector3Int((int)((float)this.Resolution.get_x() * this.ShadowsScale), (int)((float)this.Resolution.get_y() * this.ShadowsScale), (int)((float)this.Resolution.get_z() * this.ShadowsScale));
|
||||
}
|
||||
}
|
||||
|
||||
static LightVolume()
|
||||
{
|
||||
LightVolume._previewPosID = Shader.PropertyToID("_Positions");
|
||||
LightVolume._previewScaleID = Shader.PropertyToID("_Scale");
|
||||
}
|
||||
|
||||
public LightVolume()
|
||||
{
|
||||
}
|
||||
|
||||
public Matrix4x4 GetMatrixTRS()
|
||||
{
|
||||
Matrix4x4 matrix4x4 = Matrix4x4.TRS(this.GetPosition(), this.GetRotation(), this.GetScale());
|
||||
return matrix4x4;
|
||||
}
|
||||
|
||||
public Vector3[] GetOcclusionProbesPositions()
|
||||
{
|
||||
Vector3[] vector3Array = new Vector3[this.GetOcclusionVoxelCount(0)];
|
||||
Vector3 vector3 = new Vector3(0.5f, 0.5f, 0.5f);
|
||||
Vector3 position = this.GetPosition();
|
||||
Quaternion rotation = this.GetRotation();
|
||||
Vector3 scale = this.GetScale();
|
||||
int num = 0;
|
||||
Vector3Int occlusionResolution = this.OcclusionResolution;
|
||||
for (int i = 0; i < occlusionResolution.get_z(); i++)
|
||||
{
|
||||
for (int j = 0; j < occlusionResolution.get_y(); j++)
|
||||
{
|
||||
for (int k = 0; k < occlusionResolution.get_x(); k++)
|
||||
{
|
||||
Vector3 vector31 = new Vector3((float)((float)k + 0.5f) / (float)occlusionResolution.get_x(), (float)((float)j + 0.5f) / (float)occlusionResolution.get_y(), (float)((float)i + 0.5f) / (float)occlusionResolution.get_z()) - vector3;
|
||||
vector3Array[num] = LVUtils.TransformPoint(vector31, position, rotation, scale);
|
||||
num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return vector3Array;
|
||||
}
|
||||
|
||||
public int GetOcclusionVoxelCount(int padding = 0)
|
||||
{
|
||||
Vector3Int occlusionResolution = this.OcclusionResolution;
|
||||
long _x = (long)(occlusionResolution.get_x() + padding * 2);
|
||||
occlusionResolution = this.OcclusionResolution;
|
||||
long _y = _x * (long)(occlusionResolution.get_y() + padding * 2);
|
||||
occlusionResolution = this.OcclusionResolution;
|
||||
ulong _z = (ulong)(_y * (long)(occlusionResolution.get_z() + padding * 2));
|
||||
return ((_z > (long)2147483647 ? false : _z >= (long)0) ? (int)_z : -1);
|
||||
}
|
||||
|
||||
public Vector3 GetPosition()
|
||||
{
|
||||
return base.get_transform().get_position();
|
||||
}
|
||||
|
||||
public Quaternion GetRotation()
|
||||
{
|
||||
Quaternion quaternion;
|
||||
this.SetupDependencies();
|
||||
quaternion = ((!this.LightVolumeSetup.IsBakeryMode || Application.get_isPlaying() ? true : !this.Bake) ? base.get_transform().get_rotation() : Quaternion.get_identity());
|
||||
return quaternion;
|
||||
}
|
||||
|
||||
public Vector3 GetScale()
|
||||
{
|
||||
return base.get_transform().get_lossyScale();
|
||||
}
|
||||
|
||||
public int GetVoxelCount(int padding = 0)
|
||||
{
|
||||
ulong _x = (ulong)((long)(this.Resolution.get_x() + padding * 2) * (long)(this.Resolution.get_y() + padding * 2) * (long)(this.Resolution.get_z() + padding * 2));
|
||||
return ((_x > (long)2147483647 ? false : _x >= (long)0) ? (int)_x : -1);
|
||||
}
|
||||
|
||||
public void Recalculate()
|
||||
{
|
||||
if (this.AdaptiveResolution)
|
||||
{
|
||||
this.RecalculateAdaptiveResolution();
|
||||
}
|
||||
if ((!this.PreviewVoxels ? false : this.Bake))
|
||||
{
|
||||
this.RecalculateProbesPositions();
|
||||
}
|
||||
}
|
||||
|
||||
public void RecalculateAdaptiveResolution()
|
||||
{
|
||||
Vector3 scale = this.GetScale();
|
||||
scale = new Vector3(Mathf.Abs(scale.x), Mathf.Abs(scale.y), Mathf.Abs(scale.z));
|
||||
Vector3 voxelsPerUnit = scale * this.VoxelsPerUnit;
|
||||
int num = Mathf.Max((int)Mathf.Round(voxelsPerUnit.x), 1);
|
||||
int num1 = Mathf.Max((int)Mathf.Round(voxelsPerUnit.y), 1);
|
||||
int num2 = Mathf.Max((int)Mathf.Round(voxelsPerUnit.z), 1);
|
||||
this.Resolution = new Vector3Int(num, num1, num2);
|
||||
}
|
||||
|
||||
public void RecalculateProbesPositions()
|
||||
{
|
||||
this._probesPositions = new Vector3[this.GetVoxelCount(0)];
|
||||
Vector3 vector3 = new Vector3(0.5f, 0.5f, 0.5f);
|
||||
Vector3 position = this.GetPosition();
|
||||
Quaternion rotation = this.GetRotation();
|
||||
Vector3 scale = this.GetScale();
|
||||
int num = 0;
|
||||
for (int i = 0; i < this.Resolution.get_z(); i++)
|
||||
{
|
||||
for (int j = 0; j < this.Resolution.get_y(); j++)
|
||||
{
|
||||
for (int k = 0; k < this.Resolution.get_x(); k++)
|
||||
{
|
||||
Vector3 vector31 = new Vector3((float)((float)k + 0.5f) / (float)this.Resolution.get_x(), (float)((float)j + 0.5f) / (float)this.Resolution.get_y(), (float)((float)i + 0.5f) / (float)this.Resolution.get_z()) - vector3;
|
||||
this._probesPositions[num] = LVUtils.TransformPoint(vector31, position, rotation, scale);
|
||||
num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
ReflectionProbe reflectionProbe = null;
|
||||
if ((base.get_transform().get_parent() == null ? false : base.get_transform().get_parent().get_gameObject().TryGetComponent<ReflectionProbe>(ref reflectionProbe)))
|
||||
{
|
||||
Transform _transform = base.get_transform();
|
||||
Bounds _bounds = reflectionProbe.get_bounds();
|
||||
_transform.SetPositionAndRotation(_bounds.get_center(), Quaternion.get_identity());
|
||||
Transform transform = base.get_transform();
|
||||
_bounds = reflectionProbe.get_bounds();
|
||||
LVUtils.SetLossyScale(transform, _bounds.get_size(), 20);
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetProbesPositions()
|
||||
{
|
||||
this._probesPositions = new Vector3[0];
|
||||
}
|
||||
|
||||
public void SetupBakeryDependencies()
|
||||
{
|
||||
}
|
||||
|
||||
public void SetupDependencies()
|
||||
{
|
||||
if ((this.LightVolumeInstance != null ? false : !base.TryGetComponent<VRCLightVolumes.LightVolumeInstance>(ref this.LightVolumeInstance)))
|
||||
{
|
||||
this.LightVolumeInstance = base.get_gameObject().AddComponent<VRCLightVolumes.LightVolumeInstance>();
|
||||
}
|
||||
if (this.LightVolumeSetup == null)
|
||||
{
|
||||
this.LightVolumeSetup = UnityEngine.Object.FindObjectOfType<VRCLightVolumes.LightVolumeSetup>();
|
||||
if (this.LightVolumeSetup == null)
|
||||
{
|
||||
this.LightVolumeSetup = (new GameObject("Light Volume Manager")).AddComponent<VRCLightVolumes.LightVolumeSetup>();
|
||||
this.LightVolumeSetup.SyncUdonScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SyncUdonScript()
|
||||
{
|
||||
this.SetupDependencies();
|
||||
this.LightVolumeInstance.IsInitialized = true;
|
||||
this.LightVolumeInstance.LightVolumeManager = this.LightVolumeSetup.LightVolumeManager;
|
||||
this.LightVolumeInstance.IsDynamic = this.Dynamic;
|
||||
this.LightVolumeInstance.IsAdditive = this.Additive;
|
||||
this.LightVolumeInstance.Color = this.Color;
|
||||
this.LightVolumeInstance.Intensity = this.Intensity;
|
||||
this.LightVolumeInstance.SetSmoothBlending(this.SmoothBlending);
|
||||
}
|
||||
}
|
||||
}
|
18
VRCLightVolumes/LightVolumeData.cs
Normal file
18
VRCLightVolumes/LightVolumeData.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
|
||||
namespace VRCLightVolumes
|
||||
{
|
||||
[Serializable]
|
||||
public struct LightVolumeData
|
||||
{
|
||||
public float Weight;
|
||||
|
||||
public VRCLightVolumes.LightVolumeInstance LightVolumeInstance;
|
||||
|
||||
public LightVolumeData(float weight, VRCLightVolumes.LightVolumeInstance lightVolumeInstance)
|
||||
{
|
||||
this.Weight = weight;
|
||||
this.LightVolumeInstance = lightVolumeInstance;
|
||||
}
|
||||
}
|
||||
}
|
31
VRCLightVolumes/LightVolumeDataSorter.cs
Normal file
31
VRCLightVolumes/LightVolumeDataSorter.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace VRCLightVolumes
|
||||
{
|
||||
public static class LightVolumeDataSorter
|
||||
{
|
||||
public static LightVolumeInstance[] GetData(List<LightVolumeData> sortedData)
|
||||
{
|
||||
int count = sortedData.Count;
|
||||
LightVolumeInstance[] lightVolumeInstance = new LightVolumeInstance[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
lightVolumeInstance[i] = sortedData[i].LightVolumeInstance;
|
||||
}
|
||||
return lightVolumeInstance;
|
||||
}
|
||||
|
||||
public static List<LightVolumeData> SortData(List<LightVolumeData> lightVolumeDataList)
|
||||
{
|
||||
lightVolumeDataList.RemoveAll((LightVolumeData item) => item.LightVolumeInstance == null);
|
||||
List<LightVolumeData> list = (
|
||||
from item in lightVolumeDataList
|
||||
orderby item.LightVolumeInstance.IsAdditive descending, item.Weight descending
|
||||
select item).ToList<LightVolumeData>();
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
143
VRCLightVolumes/LightVolumeInstance.cs
Normal file
143
VRCLightVolumes/LightVolumeInstance.cs
Normal file
|
@ -0,0 +1,143 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRCLightVolumes
|
||||
{
|
||||
public class LightVolumeInstance : MonoBehaviour
|
||||
{
|
||||
[ColorUsage(false)]
|
||||
[Tooltip("Changing the color is useful for animating Additive volumes. You can even control the R, G, B channels separately this way.")]
|
||||
public UnityEngine.Color Color = UnityEngine.Color.get_white();
|
||||
|
||||
[Tooltip("Color multiplies by this value.")]
|
||||
public float Intensity = 1f;
|
||||
|
||||
[Tooltip("Defines whether this volume can be moved in runtime. Disabling this option slightly improves performance. You can even change it in runtime.")]
|
||||
public bool IsDynamic = false;
|
||||
|
||||
[Tooltip("Additive volumes apply their light on top of others as an overlay. Useful for movable lights like flashlights, projectors, disco balls, etc. They can also project light onto static lightmapped objects if the surface shader supports it.")]
|
||||
public bool IsAdditive = false;
|
||||
|
||||
[Tooltip("Inverse rotation of the pose the volume was baked in. Automatically recalculated for dynamic volumes with auto-update, or manually via the UpdateRotation() method.")]
|
||||
public Quaternion InvBakedRotation = Quaternion.get_identity();
|
||||
|
||||
[Space]
|
||||
[Tooltip("Min bounds of Texture0 in 3D atlas space. W stores Scale X.)")]
|
||||
public Vector4 BoundsUvwMin0 = new Vector4();
|
||||
|
||||
[Tooltip("Min bounds of Texture1 in 3D atlas space. W stores Scale Y.")]
|
||||
public Vector4 BoundsUvwMin1 = new Vector4();
|
||||
|
||||
[Tooltip("Min bounds of Texture2 in 3D atlas space. W stores Scale Z.")]
|
||||
public Vector4 BoundsUvwMin2 = new Vector4();
|
||||
|
||||
[Tooltip("Min bounds of occlusion texture in 3D atlas space.")]
|
||||
public Vector4 BoundsUvwMinOcclusion = new Vector4();
|
||||
|
||||
[Space]
|
||||
[Tooltip("Max bounds of Texture0 in 3D atlas space. (Legacy)")]
|
||||
public Vector4 BoundsUvwMax0 = new Vector4();
|
||||
|
||||
[Tooltip("Max bounds of Texture1 in 3D atlas space. (Legacy)")]
|
||||
public Vector4 BoundsUvwMax1 = new Vector4();
|
||||
|
||||
[Tooltip("Max bounds of Texture2 in 3D atlas space. (Legacy)")]
|
||||
public Vector4 BoundsUvwMax2 = new Vector4();
|
||||
|
||||
[Space]
|
||||
[Tooltip("Inversed edge smoothing in 3D atlas space. Recalculates via SetSmoothBlending(float radius) method.")]
|
||||
public Vector4 InvLocalEdgeSmoothing = new Vector4();
|
||||
|
||||
[Tooltip("Inversed TRS matrix of this volume that transforms it into the 1x1x1 cube. Recalculates via the UpdateRotation() method.")]
|
||||
public Matrix4x4 InvWorldMatrix = Matrix4x4.get_identity();
|
||||
|
||||
[Tooltip("Current volume's rotation relative to the rotation it was baked with. Mandatory for dynamic volumes. Recalculates via the UpdateRotation() method.")]
|
||||
public Vector4 RelativeRotation = new Vector4(0f, 0f, 0f, 1f);
|
||||
|
||||
[Tooltip("Current volume's rotation matrix row 0 relative to the rotation it was baked with. Mandatory for dynamic volumes. Recalculates via the UpdateRotation() method. (Legacy)")]
|
||||
public Vector3 RelativeRotationRow0 = Vector3.get_zero();
|
||||
|
||||
[Tooltip("Current volume's rotation matrix row 1 relative to the rotation it was baked with. Mandatory for dynamic volumes. Recalculates via the UpdateRotation() method. (Legacy)")]
|
||||
public Vector3 RelativeRotationRow1 = Vector3.get_zero();
|
||||
|
||||
[Tooltip("True if there is any relative rotation. No relative rotation improves performance. Recalculated via the UpdateRotation() method.")]
|
||||
public bool IsRotated = false;
|
||||
|
||||
[Tooltip("True if the volume has baked occlusion.")]
|
||||
public bool BakeOcclusion = false;
|
||||
|
||||
[Tooltip("True if this Light Volume added to the Light Volumes array in LightVolumeManager. Should be always true for the Light Volumes placed in editor. Helps to initialize Light Volumes spawned in runtime.")]
|
||||
public bool IsInitialized = false;
|
||||
|
||||
[Tooltip("Reference to the Light Volume Manager. Needed for runtime initialization.")]
|
||||
public VRCLightVolumes.LightVolumeManager LightVolumeManager;
|
||||
|
||||
[HideInInspector]
|
||||
public bool IsIterartedThrough = false;
|
||||
|
||||
private UnityEngine.Color _prevColor = UnityEngine.Color.get_white();
|
||||
|
||||
private float _prevIntensity = 1f;
|
||||
|
||||
public LightVolumeInstance()
|
||||
{
|
||||
}
|
||||
|
||||
public void DelayInitialize()
|
||||
{
|
||||
if ((this.IsInitialized ? false : this.LightVolumeManager != null))
|
||||
{
|
||||
this.LightVolumeManager.InitializeLightVolume(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (this.LightVolumeManager != null)
|
||||
{
|
||||
this.LightVolumeManager.RequestUpdateVolumes();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (this.LightVolumeManager != null)
|
||||
{
|
||||
this.LightVolumeManager.RequestUpdateVolumes();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSmoothBlending(float radius)
|
||||
{
|
||||
this.InvLocalEdgeSmoothing = base.get_transform().get_lossyScale() / Mathf.Max(radius, 1E-05f);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
this.DelayInitialize();
|
||||
if ((this._prevColor != this.Color ? true : this._prevIntensity != this.Intensity))
|
||||
{
|
||||
this._prevColor = this.Color;
|
||||
this._prevIntensity = this.Intensity;
|
||||
this.LightVolumeManager.RequestUpdateVolumes();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTransform()
|
||||
{
|
||||
Quaternion _rotation = base.get_transform().get_rotation();
|
||||
Matrix4x4 matrix4x4 = Matrix4x4.TRS(base.get_transform().get_position(), _rotation, base.get_transform().get_lossyScale());
|
||||
this.InvWorldMatrix = matrix4x4.get_inverse();
|
||||
Quaternion invBakedRotation = _rotation * this.InvBakedRotation;
|
||||
this.IsRotated = Quaternion.Dot(invBakedRotation, Quaternion.get_identity()) < 0.999999f;
|
||||
Matrix4x4 matrix4x41 = Matrix4x4.Rotate(invBakedRotation);
|
||||
Vector4 row = matrix4x41.GetRow(0);
|
||||
row.w = 0f;
|
||||
this.RelativeRotationRow0 = row;
|
||||
Vector4 vector4 = matrix4x41.GetRow(1);
|
||||
vector4.w = 0f;
|
||||
this.RelativeRotationRow1 = vector4;
|
||||
this.RelativeRotation = new Vector4(invBakedRotation.x, invBakedRotation.y, invBakedRotation.z, invBakedRotation.w);
|
||||
}
|
||||
}
|
||||
}
|
538
VRCLightVolumes/LightVolumeManager.cs
Normal file
538
VRCLightVolumes/LightVolumeManager.cs
Normal file
|
@ -0,0 +1,538 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRCLightVolumes
|
||||
{
|
||||
public class LightVolumeManager : MonoBehaviour
|
||||
{
|
||||
public const float Version = 2f;
|
||||
|
||||
[Tooltip("Combined texture containing all Light Volumes' textures.")]
|
||||
public Texture LightVolumeAtlas;
|
||||
|
||||
[Tooltip("Combined Texture3D containing all baked Light Volume data. This field is not used at runtime, see LightVolumeAtlas instead. It specifies the base for the post process chain, if given.")]
|
||||
public Texture3D LightVolumeAtlasBase;
|
||||
|
||||
[Tooltip("Custom Render Textures that will be applied top to bottom to the Light Volume Atlas at runtime. External scripts can register themselves here using `RegisterPostProcessorCRT`. You probably don't want to mess with this field manually.")]
|
||||
public CustomRenderTexture[] AtlasPostProcessors;
|
||||
|
||||
[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;
|
||||
|
||||
[Tooltip("Limits the maximum number of additive volumes that can affect a single pixel. If you have many dynamic additive volumes that may overlap, it's good practice to limit overdraw to maintain performance.")]
|
||||
public int AdditiveMaxOverdraw = 4;
|
||||
|
||||
[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;
|
||||
|
||||
[Tooltip("All Light Volume instances sorted in decreasing order by weight. You can enable or disable volumes game objects at runtime. Manually disabling unnecessary volumes improves performance.")]
|
||||
public LightVolumeInstance[] LightVolumeInstances = new LightVolumeInstance[0];
|
||||
|
||||
[Tooltip("All Point Light Volume instances. You can enable or disable point light volumes game objects at runtime. Manually disabling unnecessary point light volumes improves performance.")]
|
||||
public PointLightVolumeInstance[] PointLightVolumeInstances = new PointLightVolumeInstance[0];
|
||||
|
||||
[Tooltip("A texture array that can be used for as Cubemaps, LUT or Cookies")]
|
||||
public Texture CustomTextures;
|
||||
|
||||
[Tooltip("Cubemaps count that stored in CustomTextures. Cubemap array elements starts from the beginning, 6 elements each.")]
|
||||
public int CubemapsCount = 0;
|
||||
|
||||
[HideInInspector]
|
||||
public bool IsRangeDirty = false;
|
||||
|
||||
private bool _isInitialized = false;
|
||||
|
||||
private float _prevLightsBrightnessCutoff = 0.35f;
|
||||
|
||||
private Coroutine _updateCoroutine = null;
|
||||
|
||||
private int _enabledCount = 0;
|
||||
|
||||
private int _lastEnabledCount = -1;
|
||||
|
||||
private int _additiveCount = 0;
|
||||
|
||||
private int _occlusionCount = 0;
|
||||
|
||||
private Vector4[] _invLocalEdgeSmooth = new Vector4[0];
|
||||
|
||||
private Vector4[] _colors = new Vector4[0];
|
||||
|
||||
private Vector4[] _boundsUvwScale = new Vector4[0];
|
||||
|
||||
private Vector4[] _boundsOcclusionUvw = new Vector4[0];
|
||||
|
||||
private Vector4[] _relativeRotationQuaternion = new Vector4[0];
|
||||
|
||||
private int _pointLightCount = 0;
|
||||
|
||||
private int _lastPointLightCount = -1;
|
||||
|
||||
private int[] _enabledPointIDs = new Int32[128];
|
||||
|
||||
private Vector4[] _pointLightPosition;
|
||||
|
||||
private Vector4[] _pointLightColor;
|
||||
|
||||
private Vector4[] _pointLightDirection;
|
||||
|
||||
private Vector4[] _pointLightCustomId;
|
||||
|
||||
private Matrix4x4[] _invWorldMatrix = new Matrix4x4[0];
|
||||
|
||||
private Vector4[] _boundsUvw = new Vector4[0];
|
||||
|
||||
private Vector4[] _relativeRotation = new Vector4[0];
|
||||
|
||||
private int[] _enabledIDs = new Int32[32];
|
||||
|
||||
private Vector4[] _boundsScale = new Vector4[3];
|
||||
|
||||
private Vector4[] _bounds = new Vector4[6];
|
||||
|
||||
private int lightVolumeInvLocalEdgeSmoothID;
|
||||
|
||||
private int lightVolumeColorID;
|
||||
|
||||
private int lightVolumeCountID;
|
||||
|
||||
private int lightVolumeAdditiveCountID;
|
||||
|
||||
private int lightVolumeAdditiveMaxOverdrawID;
|
||||
|
||||
private int lightVolumeEnabledID;
|
||||
|
||||
private int lightVolumeVersionID;
|
||||
|
||||
private int lightVolumeProbesBlendID;
|
||||
|
||||
private int lightVolumeSharpBoundsID;
|
||||
|
||||
private int lightVolumeID;
|
||||
|
||||
private int lightVolumeRotationQuaternionID;
|
||||
|
||||
private int lightVolumeInvWorldMatrixID;
|
||||
|
||||
private int lightVolumeUvwScaleID;
|
||||
|
||||
private int lightVolumeOcclusionUvwID;
|
||||
|
||||
private int lightVolumeOcclusionCountID;
|
||||
|
||||
private int _pointLightPositionID;
|
||||
|
||||
private int _pointLightColorID;
|
||||
|
||||
private int _pointLightDirectionID;
|
||||
|
||||
private int _pointLightCustomIdID;
|
||||
|
||||
private int _pointLightCountID;
|
||||
|
||||
private int _pointLightCubeCountID;
|
||||
|
||||
private int _pointLightTextureID;
|
||||
|
||||
private int _lightBrightnessCutoffID;
|
||||
|
||||
private int _areaLightBrightnessCutoffID;
|
||||
|
||||
private int lightVolumeRotationID;
|
||||
|
||||
private int lightVolumeUvwID;
|
||||
|
||||
public int EnabledCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._enabledCount;
|
||||
}
|
||||
}
|
||||
|
||||
public int[] EnabledIDs
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._enabledIDs;
|
||||
}
|
||||
}
|
||||
|
||||
public LightVolumeManager()
|
||||
{
|
||||
}
|
||||
|
||||
public void InitializeLightVolume(LightVolumeInstance lightVolume)
|
||||
{
|
||||
int length = (int)this.LightVolumeInstances.Length;
|
||||
int num = 0;
|
||||
while (true)
|
||||
{
|
||||
if (num >= length)
|
||||
{
|
||||
LightVolumeInstance[] lightVolumeInstanceArray = new LightVolumeInstance[length + 1];
|
||||
Array.Copy(this.LightVolumeInstances, lightVolumeInstanceArray, length);
|
||||
lightVolumeInstanceArray[length] = lightVolume;
|
||||
lightVolume.IsInitialized = true;
|
||||
this.LightVolumeInstances = lightVolumeInstanceArray;
|
||||
break;
|
||||
}
|
||||
else if (this.LightVolumeInstances[num] != null)
|
||||
{
|
||||
num++;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.LightVolumeInstances[num] = lightVolume;
|
||||
lightVolume.IsInitialized = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void InitializePointLightVolume(PointLightVolumeInstance pointLightVolume)
|
||||
{
|
||||
int length = (int)this.PointLightVolumeInstances.Length;
|
||||
int num = 0;
|
||||
while (true)
|
||||
{
|
||||
if (num >= length)
|
||||
{
|
||||
PointLightVolumeInstance[] pointLightVolumeInstanceArray = new PointLightVolumeInstance[length + 1];
|
||||
Array.Copy(this.PointLightVolumeInstances, pointLightVolumeInstanceArray, length);
|
||||
pointLightVolumeInstanceArray[length] = pointLightVolume;
|
||||
pointLightVolume.IsInitialized = true;
|
||||
this.PointLightVolumeInstances = pointLightVolumeInstanceArray;
|
||||
break;
|
||||
}
|
||||
else if (this.PointLightVolumeInstances[num] != null)
|
||||
{
|
||||
num++;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PointLightVolumeInstances[num] = pointLightVolume;
|
||||
pointLightVolume.IsInitialized = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
this.TryInitialize();
|
||||
if ((object)this._updateCoroutine != (object)null)
|
||||
{
|
||||
base.StopCoroutine(this._updateCoroutine);
|
||||
this._updateCoroutine = null;
|
||||
}
|
||||
Shader.SetGlobalFloat(this.lightVolumeEnabledID, 0f);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
this.RequestUpdateVolumes();
|
||||
}
|
||||
|
||||
public void RequestUpdateVolumes()
|
||||
{
|
||||
if ((this._updateCoroutine != null ? false : base.get_isActiveAndEnabled()))
|
||||
{
|
||||
this._updateCoroutine = base.StartCoroutine(this.UpdateVolumesCoroutine());
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
this._isInitialized = false;
|
||||
this.UpdateVolumes();
|
||||
}
|
||||
|
||||
private void TryInitialize()
|
||||
{
|
||||
if (!this._isInitialized)
|
||||
{
|
||||
this.lightVolumeInvLocalEdgeSmoothID = Shader.PropertyToID("_UdonLightVolumeInvLocalEdgeSmooth");
|
||||
this.lightVolumeInvWorldMatrixID = Shader.PropertyToID("_UdonLightVolumeInvWorldMatrix");
|
||||
this.lightVolumeColorID = Shader.PropertyToID("_UdonLightVolumeColor");
|
||||
this.lightVolumeCountID = Shader.PropertyToID("_UdonLightVolumeCount");
|
||||
this.lightVolumeAdditiveCountID = Shader.PropertyToID("_UdonLightVolumeAdditiveCount");
|
||||
this.lightVolumeAdditiveMaxOverdrawID = Shader.PropertyToID("_UdonLightVolumeAdditiveMaxOverdraw");
|
||||
this.lightVolumeEnabledID = Shader.PropertyToID("_UdonLightVolumeEnabled");
|
||||
this.lightVolumeVersionID = Shader.PropertyToID("_UdonLightVolumeVersion");
|
||||
this.lightVolumeProbesBlendID = Shader.PropertyToID("_UdonLightVolumeProbesBlend");
|
||||
this.lightVolumeSharpBoundsID = Shader.PropertyToID("_UdonLightVolumeSharpBounds");
|
||||
this.lightVolumeID = Shader.PropertyToID("_UdonLightVolume");
|
||||
this.lightVolumeRotationQuaternionID = Shader.PropertyToID("_UdonLightVolumeRotationQuaternion");
|
||||
this.lightVolumeUvwScaleID = Shader.PropertyToID("_UdonLightVolumeUvwScale");
|
||||
this.lightVolumeOcclusionUvwID = Shader.PropertyToID("_UdonLightVolumeOcclusionUvw");
|
||||
this.lightVolumeOcclusionCountID = Shader.PropertyToID("_UdonLightVolumeOcclusionCount");
|
||||
this._pointLightPositionID = Shader.PropertyToID("_UdonPointLightVolumePosition");
|
||||
this._pointLightColorID = Shader.PropertyToID("_UdonPointLightVolumeColor");
|
||||
this._pointLightDirectionID = Shader.PropertyToID("_UdonPointLightVolumeDirection");
|
||||
this._pointLightCountID = Shader.PropertyToID("_UdonPointLightVolumeCount");
|
||||
this._pointLightCustomIdID = Shader.PropertyToID("_UdonPointLightVolumeCustomID");
|
||||
this._pointLightCubeCountID = Shader.PropertyToID("_UdonPointLightVolumeCubeCount");
|
||||
this._pointLightTextureID = Shader.PropertyToID("_UdonPointLightVolumeTexture");
|
||||
this._lightBrightnessCutoffID = Shader.PropertyToID("_UdonLightBrightnessCutoff");
|
||||
this._areaLightBrightnessCutoffID = Shader.PropertyToID("_UdonAreaLightBrightnessCutoff");
|
||||
this.lightVolumeRotationID = Shader.PropertyToID("_UdonLightVolumeRotation");
|
||||
this.lightVolumeUvwID = Shader.PropertyToID("_UdonLightVolumeUvw");
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeInvLocalEdgeSmoothID, new Vector4[32]);
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeColorID, new Vector4[32]);
|
||||
Shader.SetGlobalMatrixArray(this.lightVolumeInvWorldMatrixID, new Matrix4x4[32]);
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeRotationQuaternionID, new Vector4[32]);
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeUvwScaleID, new Vector4[96]);
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeOcclusionUvwID, new Vector4[32]);
|
||||
Shader.SetGlobalVectorArray(this._pointLightPositionID, new Vector4[128]);
|
||||
Shader.SetGlobalVectorArray(this._pointLightColorID, new Vector4[128]);
|
||||
Shader.SetGlobalVectorArray(this._pointLightDirectionID, new Vector4[128]);
|
||||
Shader.SetGlobalVectorArray(this._pointLightCustomIdID, new Vector4[128]);
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeRotationID, new Vector4[64]);
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeUvwID, new Vector4[192]);
|
||||
this._isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateVolumes()
|
||||
{
|
||||
this.TryInitialize();
|
||||
if ((!base.get_enabled() ? false : base.get_gameObject().get_activeInHierarchy()))
|
||||
{
|
||||
if (this._prevLightsBrightnessCutoff != this.LightsBrightnessCutoff)
|
||||
{
|
||||
this._prevLightsBrightnessCutoff = this.LightsBrightnessCutoff;
|
||||
this.IsRangeDirty = true;
|
||||
}
|
||||
this._enabledCount = 0;
|
||||
this._additiveCount = 0;
|
||||
this._occlusionCount = 0;
|
||||
int num = 0;
|
||||
while (true)
|
||||
{
|
||||
if ((num >= (int)this.LightVolumeInstances.Length ? true : this._enabledCount >= 32))
|
||||
{
|
||||
break;
|
||||
}
|
||||
LightVolumeInstance lightVolumeInstances = this.LightVolumeInstances[num];
|
||||
if (lightVolumeInstances != null)
|
||||
{
|
||||
if ((!lightVolumeInstances.get_gameObject().get_activeInHierarchy() || lightVolumeInstances.Intensity == 0f || !(lightVolumeInstances.Color != Color.get_black()) ? true : lightVolumeInstances.IsIterartedThrough))
|
||||
{
|
||||
lightVolumeInstances.IsIterartedThrough = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Application.get_isPlaying())
|
||||
{
|
||||
lightVolumeInstances.UpdateTransform();
|
||||
}
|
||||
else if (lightVolumeInstances.IsDynamic)
|
||||
{
|
||||
lightVolumeInstances.UpdateTransform();
|
||||
}
|
||||
if (lightVolumeInstances.IsAdditive)
|
||||
{
|
||||
this._additiveCount++;
|
||||
}
|
||||
if (lightVolumeInstances.BakeOcclusion)
|
||||
{
|
||||
this._occlusionCount++;
|
||||
}
|
||||
this._enabledIDs[this._enabledCount] = num;
|
||||
this._enabledCount++;
|
||||
lightVolumeInstances.IsIterartedThrough = true;
|
||||
}
|
||||
}
|
||||
num++;
|
||||
}
|
||||
if (this._enabledCount != this._lastEnabledCount)
|
||||
{
|
||||
this._invLocalEdgeSmooth = new Vector4[this._enabledCount];
|
||||
this._relativeRotationQuaternion = new Vector4[this._enabledCount];
|
||||
this._boundsUvwScale = new Vector4[this._enabledCount * 3];
|
||||
this._boundsOcclusionUvw = new Vector4[this._enabledCount];
|
||||
this._colors = new Vector4[this._enabledCount];
|
||||
this._invWorldMatrix = new Matrix4x4[this._enabledCount];
|
||||
this._relativeRotation = new Vector4[this._enabledCount * 2];
|
||||
this._boundsUvw = new Vector4[this._enabledCount * 6];
|
||||
this._lastEnabledCount = this._enabledCount;
|
||||
}
|
||||
for (int i = 0; i < this._enabledCount; i++)
|
||||
{
|
||||
int num1 = this._enabledIDs[i];
|
||||
int num2 = i * 2;
|
||||
int num3 = i * 3;
|
||||
int num4 = i * 6;
|
||||
LightVolumeInstance lightVolumeInstance = this.LightVolumeInstances[num1];
|
||||
lightVolumeInstance.IsIterartedThrough = false;
|
||||
this._invWorldMatrix[i] = lightVolumeInstance.InvWorldMatrix;
|
||||
this._invLocalEdgeSmooth[i] = lightVolumeInstance.InvLocalEdgeSmoothing;
|
||||
Vector4 _linear = lightVolumeInstance.Color.get_linear() * lightVolumeInstance.Intensity;
|
||||
_linear.w = (float)((lightVolumeInstance.IsRotated ? 1 : 0));
|
||||
this._colors[i] = _linear;
|
||||
this._relativeRotationQuaternion[i] = lightVolumeInstance.RelativeRotation;
|
||||
this._relativeRotation[num2] = lightVolumeInstance.RelativeRotationRow0;
|
||||
this._relativeRotation[num2 + 1] = lightVolumeInstance.RelativeRotationRow1;
|
||||
this._boundsScale[0] = lightVolumeInstance.BoundsUvwMin0;
|
||||
this._boundsScale[1] = lightVolumeInstance.BoundsUvwMin1;
|
||||
this._boundsScale[2] = lightVolumeInstance.BoundsUvwMin2;
|
||||
this._boundsOcclusionUvw[i] = (lightVolumeInstance.BakeOcclusion ? lightVolumeInstance.BoundsUvwMinOcclusion : -Vector4.get_one());
|
||||
this._bounds[0] = lightVolumeInstance.BoundsUvwMin0;
|
||||
this._bounds[1] = lightVolumeInstance.BoundsUvwMax0;
|
||||
this._bounds[2] = lightVolumeInstance.BoundsUvwMin1;
|
||||
this._bounds[3] = lightVolumeInstance.BoundsUvwMax1;
|
||||
this._bounds[4] = lightVolumeInstance.BoundsUvwMin2;
|
||||
this._bounds[5] = lightVolumeInstance.BoundsUvwMax2;
|
||||
Array.Copy(this._boundsScale, 0, this._boundsUvwScale, num3, 3);
|
||||
Array.Copy(this._bounds, 0, this._boundsUvw, num4, 6);
|
||||
}
|
||||
this._pointLightCount = 0;
|
||||
int num5 = 0;
|
||||
while (true)
|
||||
{
|
||||
if ((num5 >= (int)this.PointLightVolumeInstances.Length ? true : this._pointLightCount >= 128))
|
||||
{
|
||||
break;
|
||||
}
|
||||
PointLightVolumeInstance pointLightVolumeInstances = this.PointLightVolumeInstances[num5];
|
||||
if (pointLightVolumeInstances != null)
|
||||
{
|
||||
if (this.IsRangeDirty)
|
||||
{
|
||||
pointLightVolumeInstances.UpdateRange();
|
||||
}
|
||||
if ((!pointLightVolumeInstances.get_gameObject().get_activeInHierarchy() || pointLightVolumeInstances.Intensity == 0f || !(pointLightVolumeInstances.Color != Color.get_black()) ? true : pointLightVolumeInstances.IsIterartedThrough))
|
||||
{
|
||||
pointLightVolumeInstances.IsIterartedThrough = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Application.get_isPlaying())
|
||||
{
|
||||
pointLightVolumeInstances.UpdateTransform();
|
||||
}
|
||||
else if (pointLightVolumeInstances.IsDynamic)
|
||||
{
|
||||
pointLightVolumeInstances.UpdateTransform();
|
||||
}
|
||||
this._enabledPointIDs[this._pointLightCount] = num5;
|
||||
this._pointLightCount++;
|
||||
pointLightVolumeInstances.IsIterartedThrough = true;
|
||||
}
|
||||
}
|
||||
num5++;
|
||||
}
|
||||
this.IsRangeDirty = false;
|
||||
if (this._pointLightCount != this._lastPointLightCount)
|
||||
{
|
||||
this._pointLightPosition = new Vector4[this._pointLightCount];
|
||||
this._pointLightColor = new Vector4[this._pointLightCount];
|
||||
this._pointLightDirection = new Vector4[this._pointLightCount];
|
||||
this._pointLightCustomId = new Vector4[this._pointLightCount];
|
||||
this._lastPointLightCount = this._pointLightCount;
|
||||
}
|
||||
for (int j = 0; j < this._pointLightCount; j++)
|
||||
{
|
||||
PointLightVolumeInstance pointLightVolumeInstance = this.PointLightVolumeInstances[this._enabledPointIDs[j]];
|
||||
if ((this.IsRangeDirty ? true : pointLightVolumeInstance.IsRangeDirty))
|
||||
{
|
||||
pointLightVolumeInstance.UpdateRange();
|
||||
}
|
||||
pointLightVolumeInstance.IsIterartedThrough = false;
|
||||
Vector4 positionData = pointLightVolumeInstance.PositionData;
|
||||
if (!pointLightVolumeInstance.IsAreaLight())
|
||||
{
|
||||
if (!pointLightVolumeInstance.IsLut())
|
||||
{
|
||||
positionData.w *= pointLightVolumeInstance.SquaredScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
positionData.w /= pointLightVolumeInstance.SquaredScale;
|
||||
}
|
||||
}
|
||||
this._pointLightPosition[j] = positionData;
|
||||
Vector4 angleData = pointLightVolumeInstance.Color.get_linear() * pointLightVolumeInstance.Intensity;
|
||||
angleData.w = pointLightVolumeInstance.AngleData;
|
||||
this._pointLightColor[j] = angleData;
|
||||
this._pointLightDirection[j] = pointLightVolumeInstance.DirectionData;
|
||||
this._pointLightCustomId[j].x = pointLightVolumeInstance.CustomID;
|
||||
this._pointLightCustomId[j].y = (float)pointLightVolumeInstance.ShadowmaskIndex;
|
||||
this._pointLightCustomId[j].z = pointLightVolumeInstance.SquaredRange;
|
||||
}
|
||||
bool lightVolumeAtlas = this.LightVolumeAtlas != null;
|
||||
Shader.SetGlobalFloat(this.lightVolumeVersionID, 2f);
|
||||
if ((!lightVolumeAtlas || this._enabledCount == 0 ? this._pointLightCount != 0 : true))
|
||||
{
|
||||
if (lightVolumeAtlas)
|
||||
{
|
||||
Shader.SetGlobalTexture(this.lightVolumeID, this.LightVolumeAtlas);
|
||||
}
|
||||
Shader.SetGlobalFloat(this.lightVolumeCountID, (float)this._enabledCount);
|
||||
Shader.SetGlobalFloat(this.lightVolumeAdditiveCountID, (float)this._additiveCount);
|
||||
Shader.SetGlobalFloat(this.lightVolumeOcclusionCountID, (float)this._occlusionCount);
|
||||
Shader.SetGlobalFloat(this.lightVolumeProbesBlendID, (float)((this.LightProbesBlending ? 1 : 0)));
|
||||
Shader.SetGlobalFloat(this.lightVolumeSharpBoundsID, (float)((this.SharpBounds ? 1 : 0)));
|
||||
Shader.SetGlobalFloat(this.lightVolumeAdditiveMaxOverdrawID, (float)this.AdditiveMaxOverdraw);
|
||||
if (this._enabledCount != 0)
|
||||
{
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeInvLocalEdgeSmoothID, this._invLocalEdgeSmooth);
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeUvwScaleID, this._boundsUvwScale);
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeOcclusionUvwID, this._boundsOcclusionUvw);
|
||||
Shader.SetGlobalMatrixArray(this.lightVolumeInvWorldMatrixID, this._invWorldMatrix);
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeRotationQuaternionID, this._relativeRotationQuaternion);
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeColorID, this._colors);
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeUvwID, this._boundsUvw);
|
||||
Shader.SetGlobalVectorArray(this.lightVolumeRotationID, this._relativeRotation);
|
||||
}
|
||||
Shader.SetGlobalFloat(this._pointLightCountID, (float)this._pointLightCount);
|
||||
Shader.SetGlobalFloat(this._pointLightCubeCountID, (float)this.CubemapsCount);
|
||||
if (this._pointLightCount != 0)
|
||||
{
|
||||
Shader.SetGlobalVectorArray(this._pointLightColorID, this._pointLightColor);
|
||||
Shader.SetGlobalVectorArray(this._pointLightPositionID, this._pointLightPosition);
|
||||
Shader.SetGlobalVectorArray(this._pointLightDirectionID, this._pointLightDirection);
|
||||
Shader.SetGlobalVectorArray(this._pointLightCustomIdID, this._pointLightCustomId);
|
||||
Shader.SetGlobalFloat(this._lightBrightnessCutoffID, this.LightsBrightnessCutoff);
|
||||
Shader.SetGlobalFloat(this._areaLightBrightnessCutoffID, this.LightsBrightnessCutoff);
|
||||
}
|
||||
if (this.CustomTextures != null)
|
||||
{
|
||||
Shader.SetGlobalTexture(this._pointLightTextureID, this.CustomTextures);
|
||||
}
|
||||
Shader.SetGlobalFloat(this.lightVolumeEnabledID, 1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Shader.SetGlobalFloat(this.lightVolumeEnabledID, 0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Shader.SetGlobalFloat(this.lightVolumeEnabledID, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator UpdateVolumesCoroutine()
|
||||
{
|
||||
do
|
||||
{
|
||||
yield return null;
|
||||
this.UpdateVolumes();
|
||||
}
|
||||
while (this.AutoUpdateVolumes);
|
||||
this._updateCoroutine = null;
|
||||
}
|
||||
}
|
||||
}
|
335
VRCLightVolumes/LightVolumeSetup.cs
Normal file
335
VRCLightVolumes/LightVolumeSetup.cs
Normal file
|
@ -0,0 +1,335 @@
|
|||
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
|
||||
}
|
||||
}
|
||||
}
|
268
VRCLightVolumes/PointLightVolume.cs
Normal file
268
VRCLightVolumes/PointLightVolume.cs
Normal file
|
@ -0,0 +1,268 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRCLightVolumes
|
||||
{
|
||||
[ExecuteAlways]
|
||||
public class PointLightVolume : MonoBehaviour
|
||||
{
|
||||
[Tooltip("Defines whether this point light volume can be moved in runtime. Disabling this option slightly improves performance.")]
|
||||
public bool Dynamic = false;
|
||||
|
||||
[Tooltip("Enables baked shadows for this light. This setting is only available for static lights, which cannot move. You must re-bake your volumes after changing this setting. This incurs some runtime VRAM and performance overhead.")]
|
||||
public bool BakedShadows = false;
|
||||
|
||||
[Min(0f)]
|
||||
[Tooltip("Shadow radius for the baked shadows. Higher values will produce softer shadows.")]
|
||||
public float BakedShadowRadius = 0.1f;
|
||||
|
||||
[Tooltip("Point light is the most performant type. Area light is the heaviest and best suited for dynamic, movable sources. For static lighting, it's recommended to bake regular additive light volumes instead.")]
|
||||
public PointLightVolume.LightType Type = PointLightVolume.LightType.PointLight;
|
||||
|
||||
[Min(0.0001f)]
|
||||
[Tooltip("Physical radius of a light source if it was a matte glowing sphere for a point light, or a flashlight reflector for a spot light. Larger size emmits more light without increasing overall intensity.")]
|
||||
public float LightSourceSize = 0.25f;
|
||||
|
||||
[Min(0.0001f)]
|
||||
[Tooltip("Radius in meters beyond which light is culled. Fewer overlapping lights result in better performance.")]
|
||||
public float Range = 10f;
|
||||
|
||||
[ColorUsage(false)]
|
||||
[Tooltip("Multiplies the point light volume’s color by this value.")]
|
||||
public UnityEngine.Color Color = UnityEngine.Color.get_white();
|
||||
|
||||
[Tooltip("Brightness of the point light volume.")]
|
||||
public float Intensity = 1f;
|
||||
|
||||
[Tooltip("Parametric uses settings to compute light falloff. LUT uses a texture: X - cone falloff, Y - attenuation (Y only for point lights). Cookie projects a texture for spot lights. Cubemap projects a cubemap for point lights.")]
|
||||
public PointLightVolume.LightShape Shape = PointLightVolume.LightShape.Parametric;
|
||||
|
||||
[Range(0.1f, 360f)]
|
||||
[Tooltip("Angle of a spotlight cone in degrees.")]
|
||||
public float Angle = 60f;
|
||||
|
||||
[Range(0.001f, 1f)]
|
||||
[Tooltip("Cone falloff.")]
|
||||
public float Falloff = 1f;
|
||||
|
||||
[Tooltip("X - cone falloff, Y - attenuation. No compression and RGBA Float or RGBA Half format is recommended.")]
|
||||
public Texture2D FalloffLUT = null;
|
||||
|
||||
[Tooltip("Projects a square texture for spot lights.")]
|
||||
public Texture2D Cookie = null;
|
||||
|
||||
[Tooltip("Projects a cubemap for point lights.")]
|
||||
public UnityEngine.Cubemap Cubemap = null;
|
||||
|
||||
[Tooltip("Shows overdrawing range gizmo. Less point light volumes intersections - more performance!")]
|
||||
public bool DebugRange = false;
|
||||
|
||||
public int CustomID = 0;
|
||||
|
||||
public VRCLightVolumes.PointLightVolumeInstance PointLightVolumeInstance;
|
||||
|
||||
public VRCLightVolumes.LightVolumeSetup LightVolumeSetup;
|
||||
|
||||
private Texture2D _falloffLUTPrev = null;
|
||||
|
||||
private Texture2D _cookiePrev = null;
|
||||
|
||||
private UnityEngine.Cubemap _cubemapPrev = null;
|
||||
|
||||
private PointLightVolume.LightShape _shapePrev = PointLightVolume.LightShape.Parametric;
|
||||
|
||||
private PointLightVolume.LightType _typePrev = PointLightVolume.LightType.PointLight;
|
||||
|
||||
private Vector3 _prevPos = Vector3.get_zero();
|
||||
|
||||
private Quaternion _prevRot = Quaternion.get_identity();
|
||||
|
||||
private Vector3 _prevScl = Vector3.get_one();
|
||||
|
||||
private bool _isValidated = false;
|
||||
|
||||
public PointLightVolume()
|
||||
{
|
||||
}
|
||||
|
||||
public Texture GetCustomTexture()
|
||||
{
|
||||
Texture falloffLUT;
|
||||
if ((this.Shape == PointLightVolume.LightShape.Parametric ? false : this.Type != PointLightVolume.LightType.AreaLight))
|
||||
{
|
||||
if (this.Type != PointLightVolume.LightType.PointLight)
|
||||
{
|
||||
if (this.Type == PointLightVolume.LightType.SpotLight)
|
||||
{
|
||||
if (this.Shape == PointLightVolume.LightShape.LUT)
|
||||
{
|
||||
falloffLUT = this.FalloffLUT;
|
||||
return falloffLUT;
|
||||
}
|
||||
else if (this.Shape == PointLightVolume.LightShape.Custom)
|
||||
{
|
||||
falloffLUT = this.Cookie;
|
||||
return falloffLUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.Shape == PointLightVolume.LightShape.LUT)
|
||||
{
|
||||
falloffLUT = this.FalloffLUT;
|
||||
return falloffLUT;
|
||||
}
|
||||
else if (this.Shape == PointLightVolume.LightShape.Custom)
|
||||
{
|
||||
falloffLUT = this.Cubemap;
|
||||
return falloffLUT;
|
||||
}
|
||||
falloffLUT = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
falloffLUT = null;
|
||||
}
|
||||
return falloffLUT;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (this.LightVolumeSetup != null)
|
||||
{
|
||||
this.FalloffLUT = null;
|
||||
this.Cookie = null;
|
||||
this.Cubemap = null;
|
||||
this.LightVolumeSetup.RefreshVolumesList();
|
||||
this.LightVolumeSetup.SyncUdonScript();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (this.LightVolumeSetup != null)
|
||||
{
|
||||
this.LightVolumeSetup.RefreshVolumesList();
|
||||
this.LightVolumeSetup.SyncUdonScript();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
this.SetupDependencies();
|
||||
this.LightVolumeSetup.RefreshVolumesList();
|
||||
this.LightVolumeSetup.SyncUdonScript();
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
this._isValidated = true;
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
this.SetupDependencies();
|
||||
this.SyncUdonScript();
|
||||
this.LightVolumeSetup.RefreshVolumesList();
|
||||
this.LightVolumeSetup.SyncUdonScript();
|
||||
}
|
||||
|
||||
public void SetupDependencies()
|
||||
{
|
||||
if ((this.PointLightVolumeInstance != null ? false : !base.TryGetComponent<VRCLightVolumes.PointLightVolumeInstance>(ref this.PointLightVolumeInstance)))
|
||||
{
|
||||
this.PointLightVolumeInstance = base.get_gameObject().AddComponent<VRCLightVolumes.PointLightVolumeInstance>();
|
||||
}
|
||||
if (this.LightVolumeSetup == null)
|
||||
{
|
||||
this.LightVolumeSetup = UnityEngine.Object.FindObjectOfType<VRCLightVolumes.LightVolumeSetup>();
|
||||
if (this.LightVolumeSetup == null)
|
||||
{
|
||||
this.LightVolumeSetup = (new GameObject("Light Volume Manager")).AddComponent<VRCLightVolumes.LightVolumeSetup>();
|
||||
this.LightVolumeSetup.SyncUdonScript();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SyncUdonScript()
|
||||
{
|
||||
if (base.get_gameObject() != null)
|
||||
{
|
||||
this.SetupDependencies();
|
||||
this.PointLightVolumeInstance.IsInitialized = true;
|
||||
this.PointLightVolumeInstance.LightVolumeManager = this.LightVolumeSetup.LightVolumeManager;
|
||||
this.PointLightVolumeInstance.IsDynamic = this.Dynamic;
|
||||
this.PointLightVolumeInstance.Color = this.Color;
|
||||
this.PointLightVolumeInstance.Intensity = this.Intensity;
|
||||
this.PointLightVolumeInstance.IsRangeDirty = true;
|
||||
if (this.Type == PointLightVolume.LightType.PointLight)
|
||||
{
|
||||
if ((this.Shape != PointLightVolume.LightShape.Custom ? false : this.Cubemap != null))
|
||||
{
|
||||
this.PointLightVolumeInstance.SetLightSourceSize(this.LightSourceSize);
|
||||
this.PointLightVolumeInstance.SetCustomTexture(this.CustomID);
|
||||
}
|
||||
else if ((this.Shape != PointLightVolume.LightShape.LUT ? true : this.FalloffLUT == null))
|
||||
{
|
||||
this.PointLightVolumeInstance.SetLightSourceSize(this.LightSourceSize);
|
||||
this.PointLightVolumeInstance.SetParametric();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PointLightVolumeInstance.SetLightSourceSize(this.Range);
|
||||
this.PointLightVolumeInstance.SetLut(this.CustomID);
|
||||
}
|
||||
this.PointLightVolumeInstance.SetPointLight();
|
||||
this.PointLightVolumeInstance.UpdateRotation();
|
||||
}
|
||||
else if (this.Type == PointLightVolume.LightType.SpotLight)
|
||||
{
|
||||
this.PointLightVolumeInstance.SetLightSourceSize(this.Range);
|
||||
if ((this.Shape != PointLightVolume.LightShape.Custom ? false : this.Cookie != null))
|
||||
{
|
||||
this.PointLightVolumeInstance.SetLightSourceSize(this.LightSourceSize);
|
||||
this.PointLightVolumeInstance.SetCustomTexture(this.CustomID);
|
||||
}
|
||||
else if ((this.Shape != PointLightVolume.LightShape.LUT ? true : this.FalloffLUT == null))
|
||||
{
|
||||
this.PointLightVolumeInstance.SetLightSourceSize(this.LightSourceSize);
|
||||
this.PointLightVolumeInstance.SetParametric();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PointLightVolumeInstance.SetLightSourceSize(this.Range);
|
||||
this.PointLightVolumeInstance.SetLut(this.CustomID);
|
||||
}
|
||||
this.PointLightVolumeInstance.SetSpotLight(this.Angle, this.Falloff);
|
||||
this.PointLightVolumeInstance.UpdateRotation();
|
||||
}
|
||||
else if (this.Type == PointLightVolume.LightType.AreaLight)
|
||||
{
|
||||
this.PointLightVolumeInstance.SetAreaLight();
|
||||
this.PointLightVolumeInstance.UpdateRotation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (base.get_gameObject() != null)
|
||||
{
|
||||
this.SetupDependencies();
|
||||
}
|
||||
}
|
||||
|
||||
public enum LightShape
|
||||
{
|
||||
Parametric,
|
||||
LUT,
|
||||
Custom
|
||||
}
|
||||
|
||||
public enum LightType
|
||||
{
|
||||
PointLight,
|
||||
SpotLight,
|
||||
AreaLight
|
||||
}
|
||||
}
|
||||
}
|
313
VRCLightVolumes/PointLightVolumeInstance.cs
Normal file
313
VRCLightVolumes/PointLightVolumeInstance.cs
Normal file
|
@ -0,0 +1,313 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace VRCLightVolumes
|
||||
{
|
||||
public class PointLightVolumeInstance : MonoBehaviour
|
||||
{
|
||||
[ColorUsage(false)]
|
||||
[Tooltip("Point light volume color")]
|
||||
public UnityEngine.Color Color;
|
||||
|
||||
[Tooltip("Color multiplies by this value.")]
|
||||
public float Intensity = 1f;
|
||||
|
||||
[Tooltip("Defines whether this point light volume can be moved in runtime. Disabling this option slightly improves performance.")]
|
||||
public bool IsDynamic = false;
|
||||
|
||||
[Tooltip("For point light: XYZ = Position, W = Inverse squared range.\nFor spot light: XYZ = Position, W = Inverse squared range, negated.\nFor area light: XYZ = Position, W = Width.")]
|
||||
public Vector4 PositionData;
|
||||
|
||||
[Tooltip("For point light: XYZW = Rotation quaternion.\nFor spot light: XYZ = Direction, W = Cone falloff.\nFor area light: XYZW = Rotation quaternion.")]
|
||||
public Vector4 DirectionData;
|
||||
|
||||
[Tooltip("If parametric: Stores 0.\nIf uses custom LUT: Stores LUT ID with positive sign.\nIf uses custom texture: Stores texture ID with negative sign.")]
|
||||
public float CustomID;
|
||||
|
||||
[Tooltip("Half-angle of the spotlight cone, in radians.")]
|
||||
public float Angle;
|
||||
|
||||
[Tooltip("For point light: unused.\nFor spot light: Cos of outer angle if no custom texture, tan of outer angle otherwise.\nFor area light: 2 + Height.")]
|
||||
public float AngleData;
|
||||
|
||||
[Tooltip("Index of the shadowmask channel used by this light. -1 means no shadowmask.")]
|
||||
public sbyte ShadowmaskIndex = -1;
|
||||
|
||||
[Tooltip("True if this Point Light Volume added to the Point Light Volumes array in LightVolumeManager. Should be always true for the Point Light Volumes placed in editor. Helps to initialize Point Light Volumes spawned in runtime.")]
|
||||
public bool IsInitialized = false;
|
||||
|
||||
[Tooltip("Squared range after which light will be culled. Should be recalculated by executing UpdateRange() method.")]
|
||||
public float SquaredRange = 1f;
|
||||
|
||||
[Tooltip("Average squared lossy scale of the light. Light Source Size gets multiplied by it at the end. Updates with UpdateTransform() method.")]
|
||||
public float SquaredScale = 1f;
|
||||
|
||||
[Tooltip("Reference to the Light Volume Manager. Needed for runtime initialization.")]
|
||||
public VRCLightVolumes.LightVolumeManager LightVolumeManager;
|
||||
|
||||
[HideInInspector]
|
||||
public bool IsIterartedThrough = false;
|
||||
|
||||
[HideInInspector]
|
||||
public bool IsRangeDirty = false;
|
||||
|
||||
private Vector3 _prevPosition = Vector3.get_zero();
|
||||
|
||||
private Quaternion _prevRotation = Quaternion.get_identity();
|
||||
|
||||
private Vector3 _prevScale = Vector3.get_one();
|
||||
|
||||
public PointLightVolumeInstance()
|
||||
{
|
||||
}
|
||||
|
||||
private float ComputeAreaLightSquaredBoundingSphere(float width, float height, UnityEngine.Color color, float intensity, float cutoff)
|
||||
{
|
||||
float single = Mathf.Clamp(cutoff / (Mathf.Max(color.r, Mathf.Max(color.g, color.b)) * intensity), -6.2831855f, 6.2831855f);
|
||||
float single1 = width * height;
|
||||
float single2 = width * width;
|
||||
float single3 = 0.25f * (single2 + height * height);
|
||||
float single4 = Mathf.Tan(0.25f * single);
|
||||
float single5 = single4 * single4;
|
||||
float single6 = single5 * single3;
|
||||
float single7 = Mathf.Sqrt(single6 * single6 + 4f * single5 * single1 * single1);
|
||||
return (single7 - single6) * 0.125f / single5;
|
||||
}
|
||||
|
||||
private float ComputePointLightSquaredBoundingSphere(UnityEngine.Color color, float intensity, float sqSize, float cutoff)
|
||||
{
|
||||
float single = Mathf.Max(color.r, Mathf.Max(color.g, color.b));
|
||||
float single1 = Mathf.Max(6.2831855f * single * Mathf.Abs(intensity) / (cutoff * cutoff) - 1f, 0f) * sqSize;
|
||||
return single1;
|
||||
}
|
||||
|
||||
public bool IsAreaLight()
|
||||
{
|
||||
return (this.PositionData.w < 0f ? false : (double)this.AngleData > 1.5);
|
||||
}
|
||||
|
||||
public bool IsCustomTexture()
|
||||
{
|
||||
return this.CustomID < 0f;
|
||||
}
|
||||
|
||||
public bool IsLut()
|
||||
{
|
||||
return this.CustomID > 0f;
|
||||
}
|
||||
|
||||
public bool IsParametric()
|
||||
{
|
||||
return this.CustomID == 0f;
|
||||
}
|
||||
|
||||
public bool IsPointLight()
|
||||
{
|
||||
return (this.PositionData.w < 0f ? false : (double)this.AngleData <= 1.5);
|
||||
}
|
||||
|
||||
public bool IsSpotLight()
|
||||
{
|
||||
return this.PositionData.w < 0f;
|
||||
}
|
||||
|
||||
private void MarkRangeDirtyAndRequestUpdate()
|
||||
{
|
||||
this.IsRangeDirty = true;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (this.LightVolumeManager != null)
|
||||
{
|
||||
this.LightVolumeManager.RequestUpdateVolumes();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (this.LightVolumeManager != null)
|
||||
{
|
||||
this.LightVolumeManager.RequestUpdateVolumes();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAreaLight()
|
||||
{
|
||||
this.PositionData.w = Mathf.Max(Mathf.Abs(base.get_transform().get_lossyScale().x), 0.001f);
|
||||
this.AngleData = 2f + Mathf.Max(Mathf.Abs(base.get_transform().get_lossyScale().y), 0.001f);
|
||||
this.MarkRangeDirtyAndRequestUpdate();
|
||||
}
|
||||
|
||||
public void SetColor(UnityEngine.Color color)
|
||||
{
|
||||
this.Color = color;
|
||||
this.MarkRangeDirtyAndRequestUpdate();
|
||||
}
|
||||
|
||||
public void SetCustomTexture(int id)
|
||||
{
|
||||
this.CustomID = (float)(-id - 1);
|
||||
if (this.IsSpotLight())
|
||||
{
|
||||
this.AngleData = Mathf.Tan(this.Angle);
|
||||
}
|
||||
this.MarkRangeDirtyAndRequestUpdate();
|
||||
}
|
||||
|
||||
public void SetIntensity(float intensity)
|
||||
{
|
||||
this.Intensity = intensity;
|
||||
this.MarkRangeDirtyAndRequestUpdate();
|
||||
}
|
||||
|
||||
public void SetLightSourceSize(float size)
|
||||
{
|
||||
if (!this.IsLut())
|
||||
{
|
||||
this.PositionData.w = Mathf.Sign(this.PositionData.w) * size * size;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PositionData.w = Mathf.Sign(this.PositionData.w) / (size * size);
|
||||
}
|
||||
this.MarkRangeDirtyAndRequestUpdate();
|
||||
}
|
||||
|
||||
public void SetLut(int id)
|
||||
{
|
||||
this.CustomID = (float)(id + 1);
|
||||
this.AngleData = Mathf.Cos(this.Angle);
|
||||
this.MarkRangeDirtyAndRequestUpdate();
|
||||
}
|
||||
|
||||
public void SetParametric()
|
||||
{
|
||||
this.CustomID = 0f;
|
||||
this.AngleData = Mathf.Cos(this.Angle);
|
||||
this.MarkRangeDirtyAndRequestUpdate();
|
||||
}
|
||||
|
||||
public void SetPointLight()
|
||||
{
|
||||
this.PositionData.w = Mathf.Abs(this.PositionData.w);
|
||||
this.MarkRangeDirtyAndRequestUpdate();
|
||||
}
|
||||
|
||||
public void SetSpotLight(float angleDeg, float falloff)
|
||||
{
|
||||
this.Angle = angleDeg * 0.017453292f * 0.5f;
|
||||
if (!this.IsCustomTexture())
|
||||
{
|
||||
this.AngleData = Mathf.Cos(this.Angle);
|
||||
this.DirectionData.w = 1f / (Mathf.Cos(this.Angle * (1f - Mathf.Clamp01(falloff))) - this.AngleData);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.AngleData = Mathf.Tan(this.Angle);
|
||||
}
|
||||
this.PositionData.w = -Mathf.Abs(this.PositionData.w);
|
||||
this.MarkRangeDirtyAndRequestUpdate();
|
||||
}
|
||||
|
||||
public void SetSpotLight(float angleDeg)
|
||||
{
|
||||
this.Angle = angleDeg * 0.017453292f * 0.5f;
|
||||
if (!this.IsCustomTexture())
|
||||
{
|
||||
this.AngleData = Mathf.Cos(this.Angle);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.AngleData = Mathf.Tan(this.Angle);
|
||||
}
|
||||
this.PositionData.w = -Mathf.Abs(this.PositionData.w);
|
||||
this.MarkRangeDirtyAndRequestUpdate();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if ((this.IsInitialized ? false : this.LightVolumeManager != null))
|
||||
{
|
||||
this.LightVolumeManager.InitializePointLightVolume(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdatePosition()
|
||||
{
|
||||
Vector3 _position = base.get_transform().get_position();
|
||||
this.PositionData = new Vector4(_position.x, _position.y, _position.z, this.PositionData.w);
|
||||
}
|
||||
|
||||
public void UpdateRange()
|
||||
{
|
||||
float single = (this.LightVolumeManager != null ? this.LightVolumeManager.LightsBrightnessCutoff : 0.35f);
|
||||
if (this.IsAreaLight())
|
||||
{
|
||||
this.SquaredRange = this.ComputeAreaLightSquaredBoundingSphere(Mathf.Abs(this.SquaredScale / this.PositionData.w), this.AngleData - 2f, this.Color, this.Intensity * 3.1415927f, single);
|
||||
}
|
||||
else if (!this.IsLut())
|
||||
{
|
||||
this.SquaredRange = this.ComputePointLightSquaredBoundingSphere(this.Color, this.Intensity, Mathf.Abs(this.SquaredScale * this.PositionData.w), single);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SquaredRange = Mathf.Abs(this.SquaredScale / this.PositionData.w);
|
||||
}
|
||||
this.IsRangeDirty = false;
|
||||
}
|
||||
|
||||
public void UpdateRotation()
|
||||
{
|
||||
Quaternion _rotation = base.get_transform().get_rotation();
|
||||
if (this.IsAreaLight())
|
||||
{
|
||||
this.DirectionData = new Vector4(_rotation.x, _rotation.y, _rotation.z, _rotation.w);
|
||||
}
|
||||
else if ((!this.IsSpotLight() ? false : !this.IsCustomTexture()))
|
||||
{
|
||||
Vector3 _forward = base.get_transform().get_forward();
|
||||
this.DirectionData = new Vector4(_forward.x, _forward.y, _forward.z, this.DirectionData.w);
|
||||
}
|
||||
else if (!this.IsParametric())
|
||||
{
|
||||
_rotation = Quaternion.Inverse(_rotation);
|
||||
this.DirectionData = new Vector4(_rotation.x, _rotation.y, _rotation.z, _rotation.w);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateScale()
|
||||
{
|
||||
Vector3 _lossyScale = base.get_transform().get_lossyScale();
|
||||
if (this.IsAreaLight())
|
||||
{
|
||||
this.SetAreaLight();
|
||||
}
|
||||
this.SquaredScale = (_lossyScale.x + _lossyScale.y + _lossyScale.z) / 3f;
|
||||
this.SquaredScale *= this.SquaredScale;
|
||||
this.MarkRangeDirtyAndRequestUpdate();
|
||||
}
|
||||
|
||||
public void UpdateTransform()
|
||||
{
|
||||
Vector3 _position = base.get_transform().get_position();
|
||||
if (this._prevPosition != _position)
|
||||
{
|
||||
this._prevPosition = _position;
|
||||
this.UpdatePosition();
|
||||
}
|
||||
Quaternion _rotation = base.get_transform().get_rotation();
|
||||
if (this._prevRotation != _rotation)
|
||||
{
|
||||
this._prevRotation = _rotation;
|
||||
this.UpdateRotation();
|
||||
}
|
||||
Vector3 _lossyScale = base.get_transform().get_lossyScale();
|
||||
if (this._prevScale != _lossyScale)
|
||||
{
|
||||
this._prevScale = _lossyScale;
|
||||
this.UpdateScale();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
94
red.sim.LightVolumesUdon.csproj
Normal file
94
red.sim.LightVolumesUdon.csproj
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{8F01D4AC-4CB3-4704-9526-A79C2533DBC4}</ProjectGuid>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<AssemblyName>red.sim.LightVolumesUdon</AssemblyName>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFrameworkVersion>vnetstandard2.1</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<Optimize>false</Optimize>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DebugType>full</DebugType>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="netstandard">
|
||||
<HintPath>./red.sim.LightVolumesUdonReferences/netstandard.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MelonLoader, Version=0.6.6.0, Culture=neutral, PublicKeyToken=null" />
|
||||
<Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" />
|
||||
<Reference Include="Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" />
|
||||
<Reference Include="System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" />
|
||||
<Reference Include="System.Runtime">
|
||||
<HintPath>./red.sim.LightVolumesUdonReferences/System.Runtime.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties/AssemblyInfo.cs">
|
||||
<AutoGen>false</AutoGen>
|
||||
<DesignTimeSharedInput>false</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="VRCLightVolumes/LightVolumeData.cs">
|
||||
<AutoGen>false</AutoGen>
|
||||
<DesignTimeSharedInput>false</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="VRCLightVolumes/LightVolumeInstance.cs">
|
||||
<AutoGen>false</AutoGen>
|
||||
<DesignTimeSharedInput>false</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="red.sim.LightVolumesUdon/Main.cs">
|
||||
<AutoGen>false</AutoGen>
|
||||
<DesignTimeSharedInput>false</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="red.sim.LightVolumesUdon/Properties/AssemblyInfoParams.cs">
|
||||
<AutoGen>false</AutoGen>
|
||||
<DesignTimeSharedInput>false</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="VRCLightVolumes/LightVolumeSetup.cs">
|
||||
<AutoGen>false</AutoGen>
|
||||
<DesignTimeSharedInput>false</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="VRCLightVolumes/PointLightVolume.cs">
|
||||
<AutoGen>false</AutoGen>
|
||||
<DesignTimeSharedInput>false</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="VRCLightVolumes/LightVolumeManager.cs">
|
||||
<AutoGen>false</AutoGen>
|
||||
<DesignTimeSharedInput>false</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="VRCLightVolumes/LVUtils.cs">
|
||||
<AutoGen>false</AutoGen>
|
||||
<DesignTimeSharedInput>false</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="VRCLightVolumes/PointLightVolumeInstance.cs">
|
||||
<AutoGen>false</AutoGen>
|
||||
<DesignTimeSharedInput>false</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="VRCLightVolumes/LightVolume.cs">
|
||||
<AutoGen>false</AutoGen>
|
||||
<DesignTimeSharedInput>false</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<Compile Include="VRCLightVolumes/LightVolumeDataSorter.cs">
|
||||
<AutoGen>false</AutoGen>
|
||||
<DesignTimeSharedInput>false</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
21
red.sim.LightVolumesUdon.sln
Normal file
21
red.sim.LightVolumesUdon.sln
Normal file
|
@ -0,0 +1,21 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29728.190
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "red.sim.LightVolumesUdon", "red.sim.LightVolumesUdon.csproj", "{8F01D4AC-4CB3-4704-9526-A79C2533DBC4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8F01D4AC-4CB3-4704-9526-A79C2533DBC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8F01D4AC-4CB3-4704-9526-A79C2533DBC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8F01D4AC-4CB3-4704-9526-A79C2533DBC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8F01D4AC-4CB3-4704-9526-A79C2533DBC4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
30
red.sim.LightVolumesUdon/Main.cs
Normal file
30
red.sim.LightVolumesUdon/Main.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using ABI_RC.Core.Util.AssetFiltering;
|
||||
using MelonLoader;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using VRCLightVolumes;
|
||||
|
||||
namespace red.sim.LightVolumesUdon
|
||||
{
|
||||
public class Main : MelonMod
|
||||
{
|
||||
public Main()
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnInitializeMelon()
|
||||
{
|
||||
WorldFilter._Base.Add(typeof(LightVolume));
|
||||
WorldFilter._Base.Add(typeof(LightVolumeData));
|
||||
WorldFilter._Base.Add(typeof(LightVolumeDataSorter));
|
||||
WorldFilter._Base.Add(typeof(LightVolumeInstance));
|
||||
WorldFilter._Base.Add(typeof(LightVolumeManager));
|
||||
WorldFilter._Base.Add(typeof(LightVolumeSetup));
|
||||
WorldFilter._Base.Add(typeof(PointLightVolume));
|
||||
WorldFilter._Base.Add(typeof(PointLightVolumeInstance));
|
||||
SharedFilter.get_SpawnableWhitelist().Add(typeof(PointLightVolumeInstance));
|
||||
SharedFilter.get_SpawnableWhitelist().Add(typeof(PointLightVolume));
|
||||
MelonLogger.Msg("Initialized, now whitelisting modded components!");
|
||||
}
|
||||
}
|
||||
}
|
11
red.sim.LightVolumesUdon/Properties/AssemblyInfoParams.cs
Normal file
11
red.sim.LightVolumesUdon/Properties/AssemblyInfoParams.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace red.sim.LightVolumesUdon.Properties
|
||||
{
|
||||
internal static class AssemblyInfoParams
|
||||
{
|
||||
public const string Version = "1.0.0";
|
||||
|
||||
public const string Author = "REDSIM , SketchFoxsky";
|
||||
}
|
||||
}
|
BIN
red.sim.LightVolumesUdonReferences/System.Runtime.dll
Normal file
BIN
red.sim.LightVolumesUdonReferences/System.Runtime.dll
Normal file
Binary file not shown.
BIN
red.sim.LightVolumesUdonReferences/netstandard.dll
Normal file
BIN
red.sim.LightVolumesUdonReferences/netstandard.dll
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue