290 lines
No EOL
9.9 KiB
C#
290 lines
No EOL
9.9 KiB
C#
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);
|
||
}
|
||
}
|
||
} |