mirror of
https://github.com/muskit/H3VR-TNH-Quality-of-Life-Improvements.git
synced 2026-06-03 04:34:26 -07:00
Initial commit
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace SimpleLightProbePlacer
|
||||
{
|
||||
[RequireComponent(typeof(LightProbeGroup))]
|
||||
[AddComponentMenu("Rendering/Light Probe Group Control")]
|
||||
public class LightProbeGroupControl : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private float m_mergeDistance = 0.5f;
|
||||
[SerializeField] private bool m_usePointLights = true;
|
||||
[SerializeField] private float m_pointLightRange = 1;
|
||||
|
||||
public float MergeDistance { get { return m_mergeDistance; } set { m_mergeDistance = value; } }
|
||||
public int MergedProbes { get { return m_mergedProbes; } }
|
||||
public bool UsePointLights { get { return m_usePointLights; } set { m_usePointLights = value; } }
|
||||
public float PointLightRange { get { return m_pointLightRange; } set { m_pointLightRange = value; } }
|
||||
|
||||
public LightProbeGroup LightProbeGroup
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_lightProbeGroup != null) return m_lightProbeGroup;
|
||||
return m_lightProbeGroup = GetComponent<LightProbeGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
private int m_mergedProbes;
|
||||
private LightProbeGroup m_lightProbeGroup;
|
||||
|
||||
public void DeleteAll()
|
||||
{
|
||||
LightProbeGroup.probePositions = null;
|
||||
m_mergedProbes = 0;
|
||||
}
|
||||
|
||||
public void Create()
|
||||
{
|
||||
DeleteAll();
|
||||
|
||||
List<Vector3> positions = CreatePositions();
|
||||
positions.AddRange(CreateAroundPointLights(m_pointLightRange));
|
||||
positions = MergeClosestPositions(positions, m_mergeDistance, out m_mergedProbes);
|
||||
|
||||
ApplyPositions(positions);
|
||||
}
|
||||
|
||||
public void Merge()
|
||||
{
|
||||
if (LightProbeGroup.probePositions == null) return;
|
||||
|
||||
List<Vector3> positions = MergeClosestPositions(LightProbeGroup.probePositions.ToList(), m_mergeDistance, out m_mergedProbes);
|
||||
positions = positions.Select(x => transform.TransformPoint(x)).ToList();
|
||||
|
||||
ApplyPositions(positions);
|
||||
}
|
||||
|
||||
private void ApplyPositions(List<Vector3> positions)
|
||||
{
|
||||
LightProbeGroup.probePositions = positions.Select(x => transform.InverseTransformPoint(x)).ToArray();
|
||||
}
|
||||
|
||||
private static List<Vector3> CreatePositions()
|
||||
{
|
||||
var lightProbeVolumes = FindObjectsOfType<LightProbeVolume>();
|
||||
|
||||
if (lightProbeVolumes.Length == 0) return new List<Vector3>();
|
||||
|
||||
List<Vector3> probes = new List<Vector3>();
|
||||
|
||||
for (int i = 0; i < lightProbeVolumes.Length; i++)
|
||||
{
|
||||
probes.AddRange(lightProbeVolumes[i].CreatePositions());
|
||||
}
|
||||
|
||||
return probes;
|
||||
}
|
||||
|
||||
private static List<Vector3> CreateAroundPointLights(float range)
|
||||
{
|
||||
var lights = FindObjectsOfType<Light>().Where(x => x.type == LightType.Point).ToList();
|
||||
|
||||
if (lights.Count == 0) return new List<Vector3>();
|
||||
|
||||
List<Vector3> probes = new List<Vector3>();
|
||||
|
||||
for (int i = 0; i < lights.Count; i++)
|
||||
{
|
||||
probes.AddRange(CreatePositionsAround(lights[i].transform, range));
|
||||
}
|
||||
|
||||
return probes;
|
||||
}
|
||||
|
||||
private static List<Vector3> MergeClosestPositions(List<Vector3> positions, float distance, out int mergedCount)
|
||||
{
|
||||
if (positions == null)
|
||||
{
|
||||
mergedCount = 0;
|
||||
return new List<Vector3>();
|
||||
}
|
||||
|
||||
int exist = positions.Count;
|
||||
bool done = false;
|
||||
|
||||
while (!done)
|
||||
{
|
||||
Dictionary<Vector3, List<Vector3>> closest = new Dictionary<Vector3, List<Vector3>>();
|
||||
|
||||
for (int i = 0; i < positions.Count; i++)
|
||||
{
|
||||
List<Vector3> points = positions.Where(x => (x - positions[i]).magnitude < distance).ToList();
|
||||
if (points.Count > 0 && !closest.ContainsKey(positions[i]))
|
||||
{
|
||||
closest.Add(positions[i], points);
|
||||
}
|
||||
}
|
||||
|
||||
positions.Clear();
|
||||
List<Vector3> keys = closest.Keys.ToList();
|
||||
|
||||
for (int i = 0; i < keys.Count; i++)
|
||||
{
|
||||
var center = closest[keys[i]].Aggregate(Vector3.zero, (result, target) => result + target) / closest[keys[i]].Count;
|
||||
if (!positions.Exists(x => x == center)) positions.Add(center);
|
||||
}
|
||||
|
||||
done = positions.Select(x => positions.Where(y => y != x && (y - x).magnitude < distance)).All(x => !x.Any());
|
||||
}
|
||||
|
||||
mergedCount = exist - positions.Count;
|
||||
return positions;
|
||||
}
|
||||
|
||||
public static List<Vector3> CreatePositionsAround(Transform transform, float range)
|
||||
{
|
||||
Vector3[] corners =
|
||||
{
|
||||
new Vector3(-0.5f, 0.5f, -0.5f),
|
||||
new Vector3(-0.5f, 0.5f, 0.5f),
|
||||
new Vector3(0.5f, 0.5f, 0.5f),
|
||||
new Vector3(0.5f, 0.5f, -0.5f),
|
||||
new Vector3(-0.5f, -0.5f, -0.5f),
|
||||
new Vector3(-0.5f, -0.5f, 0.5f),
|
||||
new Vector3(0.5f, -0.5f, 0.5f),
|
||||
new Vector3(0.5f, -0.5f, -0.5f)
|
||||
};
|
||||
|
||||
return corners.Select(x => transform.TransformPoint(x * range)).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e58b2a5f02556c4897347a45818c57a
|
||||
timeCreated: 1457269174
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 34a11416a6b53ee4795f603273b9a46d, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,97 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SimpleLightProbePlacer
|
||||
{
|
||||
public enum LightProbeVolumeType { Fixed, Float }
|
||||
|
||||
[AddComponentMenu("Rendering/Light Probe Volume")]
|
||||
public class LightProbeVolume : TransformVolume
|
||||
{
|
||||
[SerializeField] private LightProbeVolumeType m_type = LightProbeVolumeType.Fixed;
|
||||
[SerializeField] private Vector3 m_densityFixed = Vector3.one;
|
||||
[SerializeField] private Vector3 m_densityFloat = Vector3.one;
|
||||
|
||||
public LightProbeVolumeType Type { get { return m_type; } set { m_type = value; } }
|
||||
public Vector3 Density
|
||||
{
|
||||
get { return m_type == LightProbeVolumeType.Fixed ? m_densityFixed : m_densityFloat; }
|
||||
set
|
||||
{
|
||||
if (m_type == LightProbeVolumeType.Fixed) m_densityFixed = value;
|
||||
else m_densityFloat = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static Color EditorColor { get { return new Color(1, 0.9f, 0.25f); } }
|
||||
|
||||
public List<Vector3> CreatePositions()
|
||||
{
|
||||
return CreatePositions(m_type);
|
||||
}
|
||||
|
||||
public List<Vector3> CreatePositions(LightProbeVolumeType type)
|
||||
{
|
||||
return type == LightProbeVolumeType.Fixed
|
||||
? CreatePositionsFixed(transform, Origin, Size, Density)
|
||||
: CreatePositionsFloat(transform, Origin, Size, Density);
|
||||
}
|
||||
|
||||
public static List<Vector3> CreatePositionsFixed(Transform volumeTransform, Vector3 origin, Vector3 size, Vector3 density)
|
||||
{
|
||||
List<Vector3> posList = new List<Vector3>();
|
||||
var offset = origin;
|
||||
|
||||
var moveX = size.x / Mathf.FloorToInt(density.x);
|
||||
var moveY = size.y / Mathf.FloorToInt(density.y);
|
||||
var moveZ = size.z / Mathf.FloorToInt(density.z);
|
||||
|
||||
offset -= size * 0.5f;
|
||||
|
||||
for (int x = 0; x <= density.x; x++)
|
||||
{
|
||||
for (int y = 0; y <= density.y; y++)
|
||||
{
|
||||
for (int z = 0; z <= density.z; z++)
|
||||
{
|
||||
var probePos = offset + new Vector3(x * moveX, y * moveY, z * moveZ);
|
||||
probePos = volumeTransform.TransformPoint(probePos);
|
||||
posList.Add(probePos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return posList;
|
||||
}
|
||||
|
||||
public static List<Vector3> CreatePositionsFloat(Transform volumeTransform, Vector3 origin, Vector3 size, Vector3 density)
|
||||
{
|
||||
List<Vector3> posList = new List<Vector3>();
|
||||
var offset = origin;
|
||||
|
||||
var stepX = Mathf.FloorToInt(size.x / density.x);
|
||||
var stepY = Mathf.FloorToInt(size.y / density.y);
|
||||
var stepZ = Mathf.FloorToInt(size.z / density.z);
|
||||
|
||||
offset -= size * 0.5f;
|
||||
offset.x += (size.x - stepX * density.x) * 0.5f;
|
||||
offset.y += (size.y - stepY * density.y) * 0.5f;
|
||||
offset.z += (size.z - stepZ * density.z) * 0.5f;
|
||||
|
||||
for (int x = 0; x <= stepX; x++)
|
||||
{
|
||||
for (int y = 0; y <= stepY; y++)
|
||||
{
|
||||
for (int z = 0; z <= stepZ; z++)
|
||||
{
|
||||
var probePos = offset + new Vector3(x * density.x, y * density.y, z * density.z);
|
||||
probePos = volumeTransform.TransformPoint(probePos);
|
||||
posList.Add(probePos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return posList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ce72b8e8fac84047a96f26f2b28d1d9
|
||||
timeCreated: 1457269185
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: 152cd48aa35f97f45b3522bf745d7712, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,197 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace SimpleLightProbePlacer
|
||||
{
|
||||
[AddComponentMenu("")]
|
||||
public class TransformVolume : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Volume m_volume = new Volume(Vector3.zero, Vector3.one);
|
||||
|
||||
public Volume Volume { get { return m_volume; } set { m_volume = value; } }
|
||||
public Vector3 Origin { get { return m_volume.Origin; } }
|
||||
public Vector3 Size { get { return m_volume.Size; } }
|
||||
|
||||
public bool IsInBounds(Vector3[] points)
|
||||
{
|
||||
return GetBounds().Intersects(GetBounds(points));
|
||||
}
|
||||
|
||||
public bool IsOnBorder(Vector3[] points)
|
||||
{
|
||||
if (points.All(x => !IsInVolume(x))) return false;
|
||||
|
||||
return !points.All(IsInVolume);
|
||||
}
|
||||
|
||||
public bool IsInVolume(Vector3[] points)
|
||||
{
|
||||
return points.All(IsInVolume);
|
||||
}
|
||||
|
||||
public bool IsInVolume(Vector3 position)
|
||||
{
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
var plane = new Plane(GetSideDirection(i), GetSidePosition(i));
|
||||
|
||||
if (plane.GetSide(position)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Vector3[] GetCorners()
|
||||
{
|
||||
Vector3[] corners =
|
||||
{
|
||||
new Vector3(-0.5f, 0.5f, -0.5f),
|
||||
new Vector3(-0.5f, 0.5f, 0.5f),
|
||||
new Vector3(0.5f, 0.5f, 0.5f),
|
||||
new Vector3(0.5f, 0.5f, -0.5f),
|
||||
new Vector3(-0.5f, -0.5f, -0.5f),
|
||||
new Vector3(-0.5f, -0.5f, 0.5f),
|
||||
new Vector3(0.5f, -0.5f, 0.5f),
|
||||
new Vector3(0.5f, -0.5f, -0.5f)
|
||||
};
|
||||
|
||||
for (int i = 0; i < corners.Length; i++)
|
||||
{
|
||||
corners[i].x *= m_volume.Size.x;
|
||||
corners[i].y *= m_volume.Size.y;
|
||||
corners[i].z *= m_volume.Size.z;
|
||||
|
||||
corners[i] = transform.TransformPoint(m_volume.Origin + corners[i]);
|
||||
}
|
||||
|
||||
return corners;
|
||||
}
|
||||
|
||||
public Bounds GetBounds()
|
||||
{
|
||||
return GetBounds(GetCorners());
|
||||
}
|
||||
|
||||
public Bounds GetBounds(Vector3[] points)
|
||||
{
|
||||
var center = points.Aggregate(Vector3.zero, (result, point) => result + point) / points.Length;
|
||||
var bounds = new Bounds(center, Vector3.zero);
|
||||
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
bounds.Encapsulate(points[i]);
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public GameObject[] GetGameObjectsInBounds(LayerMask layerMask)
|
||||
{
|
||||
MeshRenderer[] meshRenderers = FindObjectsOfType<MeshRenderer>();
|
||||
|
||||
List<GameObject> list = new List<GameObject>();
|
||||
|
||||
Bounds bounds = GetBounds();
|
||||
|
||||
for (int i = 0; i < meshRenderers.Length; i++)
|
||||
{
|
||||
if (meshRenderers[i].gameObject == transform.gameObject) continue;
|
||||
if (meshRenderers[i].GetComponent<TransformVolume>() != null) continue;
|
||||
if ((1 << meshRenderers[i].gameObject.layer & layerMask.value) == 0) continue;
|
||||
|
||||
if (bounds.Intersects(meshRenderers[i].bounds))
|
||||
{
|
||||
list.Add(meshRenderers[i].gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
public Vector3 GetSideDirection(int side)
|
||||
{
|
||||
Vector3[] sides = new Vector3[6];
|
||||
|
||||
var right = Vector3.right;
|
||||
var up = Vector3.up;
|
||||
var forward = Vector3.forward;
|
||||
|
||||
sides[0] = right;
|
||||
sides[1] = -right;
|
||||
sides[2] = up;
|
||||
sides[3] = -up;
|
||||
sides[4] = forward;
|
||||
sides[5] = -forward;
|
||||
|
||||
return transform.TransformDirection(sides[side]);
|
||||
}
|
||||
|
||||
public Vector3 GetSidePosition(int side)
|
||||
{
|
||||
Vector3[] sides = new Vector3[6];
|
||||
|
||||
var right = Vector3.right;
|
||||
var up = Vector3.up;
|
||||
var forward = Vector3.forward;
|
||||
|
||||
sides[0] = right;
|
||||
sides[1] = -right;
|
||||
sides[2] = up;
|
||||
sides[3] = -up;
|
||||
sides[4] = forward;
|
||||
sides[5] = -forward;
|
||||
|
||||
return transform.TransformPoint(sides[side] * GetSizeAxis(side) + m_volume.Origin);
|
||||
}
|
||||
|
||||
public float GetSizeAxis(int side)
|
||||
{
|
||||
switch (side)
|
||||
{
|
||||
case 0:
|
||||
case 1: return m_volume.Size.x * 0.5f;
|
||||
case 2:
|
||||
case 3: return m_volume.Size.y * 0.5f;
|
||||
default: return m_volume.Size.z * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static Volume EditorVolumeControl(TransformVolume transformVolume, float handleSize, Color color)
|
||||
{
|
||||
Vector3 origin, size;
|
||||
Vector3[] controlHandles = new Vector3[6];
|
||||
var transform = transformVolume.transform;
|
||||
|
||||
Handles.color = color;
|
||||
|
||||
for (int i = 0; i < controlHandles.Length; i++)
|
||||
{
|
||||
controlHandles[i] = transformVolume.GetSidePosition(i);
|
||||
}
|
||||
|
||||
controlHandles[0] = Handles.Slider(controlHandles[0], transform.right, handleSize, Handles.DotHandleCap, 1);
|
||||
controlHandles[1] = Handles.Slider(controlHandles[1], transform.right, handleSize, Handles.DotHandleCap, 1);
|
||||
controlHandles[2] = Handles.Slider(controlHandles[2], transform.up, handleSize, Handles.DotHandleCap, 1);
|
||||
controlHandles[3] = Handles.Slider(controlHandles[3], transform.up, handleSize, Handles.DotHandleCap, 1);
|
||||
controlHandles[4] = Handles.Slider(controlHandles[4], transform.forward, handleSize, Handles.DotHandleCap, 1);
|
||||
controlHandles[5] = Handles.Slider(controlHandles[5], transform.forward, handleSize, Handles.DotHandleCap, 1);
|
||||
|
||||
origin.x = transform.InverseTransformPoint((controlHandles[0] + controlHandles[1]) * 0.5f).x;
|
||||
origin.y = transform.InverseTransformPoint((controlHandles[2] + controlHandles[3]) * 0.5f).y;
|
||||
origin.z = transform.InverseTransformPoint((controlHandles[4] + controlHandles[5]) * 0.5f).z;
|
||||
|
||||
size.x = transform.InverseTransformPoint(controlHandles[0]).x - transform.InverseTransformPoint(controlHandles[1]).x;
|
||||
size.y = transform.InverseTransformPoint(controlHandles[2]).y - transform.InverseTransformPoint(controlHandles[3]).y;
|
||||
size.z = transform.InverseTransformPoint(controlHandles[4]).z - transform.InverseTransformPoint(controlHandles[5]).z;
|
||||
|
||||
return new Volume(origin, size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d839bef4d4110b244bf82bcec581a66d
|
||||
timeCreated: 1457258829
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace SimpleLightProbePlacer
|
||||
{
|
||||
[System.Serializable]
|
||||
public struct Volume
|
||||
{
|
||||
[SerializeField] private Vector3 m_origin;
|
||||
[SerializeField] private Vector3 m_size;
|
||||
|
||||
public Vector3 Origin { get { return m_origin; } }
|
||||
public Vector3 Size { get { return m_size; } }
|
||||
|
||||
public Volume(Vector3 origin, Vector3 size)
|
||||
{
|
||||
m_origin = origin;
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
public static bool operator ==(Volume left, Volume right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator !=(Volume left, Volume right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
|
||||
public bool Equals(Volume other)
|
||||
{
|
||||
return Origin == other.Origin && Size == other.Size;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
return obj is Volume && Equals((Volume) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (Origin.GetHashCode() * 397) ^ Size.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("Origin: {0}, Size: {1}", Origin, Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f270f689c223be84f93d18074813ab7f
|
||||
timeCreated: 1457259045
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user