249 lines
9.7 KiB
C#
249 lines
9.7 KiB
C#
|
using System.Collections.Generic;
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace ProbeGridAndCut
|
||
|
{
|
||
|
[ExecuteInEditMode]
|
||
|
public class ProbeGridAndCut : MonoBehaviour
|
||
|
{
|
||
|
#if UNITY_EDITOR
|
||
|
// Number of probes on each axis of the grid
|
||
|
public int probesInX = 5;
|
||
|
public int probesInY = 5;
|
||
|
public int probesInZ = 5;
|
||
|
|
||
|
// Check if only static objects will be tested
|
||
|
public bool onlyStatic = false;
|
||
|
|
||
|
//Set editor to save if something change. Used in ProbeGridAndCutEditor.cs
|
||
|
public bool somethingChanged = false;
|
||
|
|
||
|
// List of tags that will be tested in raycastAll
|
||
|
public List<string> BoundaryTags = new List<string> { "Untagged" };
|
||
|
|
||
|
// Size of raycast from each probe
|
||
|
public float rayTestSizeInsideObject = 2.5f;
|
||
|
public float rayTestSizeFarObject = 1.5f;
|
||
|
|
||
|
//Light Probe Group in Editor
|
||
|
LightProbeGroup probeGroup;
|
||
|
|
||
|
//Internal List of Light Probe Positions
|
||
|
private List<Vector3> probePositions;
|
||
|
public int probeCount = 0;
|
||
|
|
||
|
void Start()
|
||
|
{
|
||
|
probeGroup = GetComponent<LightProbeGroup>();
|
||
|
if (probeGroup == null) probeGroup = gameObject.AddComponent<LightProbeGroup>();
|
||
|
probePositions = new List<Vector3>(probeGroup.probePositions);
|
||
|
probeCount = probeGroup.probePositions.Length;
|
||
|
}
|
||
|
|
||
|
private void OnDrawGizmosSelected()
|
||
|
{
|
||
|
Gizmos.color = Color.red;
|
||
|
Gizmos.matrix = transform.localToWorldMatrix;
|
||
|
Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
|
||
|
}
|
||
|
|
||
|
public void UpdateProbes()
|
||
|
{
|
||
|
// Update Light Probe Group in Editor
|
||
|
probeGroup.probePositions = probePositions.ToArray();
|
||
|
probeCount = probeGroup.probePositions.Length;
|
||
|
}
|
||
|
|
||
|
public void Generate()
|
||
|
{
|
||
|
probePositions.Clear();
|
||
|
|
||
|
// Position relative to parent, between 0 and 1
|
||
|
Vector3 position;
|
||
|
|
||
|
// Calculating steps on each exis, lenght between 0 and 1
|
||
|
float stepX = 1f / (probesInX - 1);
|
||
|
float stepY = 1f / (probesInY - 1);
|
||
|
float stepZ = 1f / (probesInZ - 1);
|
||
|
|
||
|
// Start position relative to the parent center. (Relative parent size is always 1)
|
||
|
Vector3 startPosition = new Vector3(-0.5f, -0.5f, -0.5f);
|
||
|
|
||
|
// Populate probe position Array
|
||
|
for (int x = 0; x < probesInX; x++)
|
||
|
{
|
||
|
for (int y = 0; y < probesInY; y++)
|
||
|
{
|
||
|
for (int z = 0; z < probesInZ; z++)
|
||
|
{
|
||
|
position.x = startPosition.x + stepX * x;
|
||
|
position.y = startPosition.y + stepY * y;
|
||
|
position.z = startPosition.z + stepZ * z;
|
||
|
probePositions.Add(position);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void CutTaggedObjects()
|
||
|
{
|
||
|
Vector3 center = transform.position;
|
||
|
Vector3 position;
|
||
|
Vector3 direction;
|
||
|
float distance;
|
||
|
|
||
|
// Array with all hits from the center to the probe
|
||
|
RaycastHit[] hitAll;
|
||
|
|
||
|
// Removing from the end of the list to the beginning
|
||
|
for (int i = probePositions.Count - 1; i >= 0; i--)
|
||
|
{
|
||
|
position = transform.TransformPoint(probePositions[i]);
|
||
|
direction = position - center;
|
||
|
distance = Vector3.Distance(center, position);
|
||
|
|
||
|
// Trace a raycast from the center to the probe. If hit a tagged object the probe is removed from the list.
|
||
|
Debug.DrawLine(center, position, Color.yellow, 1);
|
||
|
hitAll = Physics.RaycastAll(center, direction, distance);
|
||
|
for (int j = 0; j < hitAll.Length; j++)
|
||
|
{
|
||
|
if (BoundaryTags.Contains(hitAll[j].transform.gameObject.tag) &&
|
||
|
!hitAll[j].transform.gameObject.CompareTag("Untagged") &&
|
||
|
(hitAll[j].collider.gameObject.isStatic || !onlyStatic))
|
||
|
{
|
||
|
probePositions.RemoveAt(i);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void CutInsideObjects()
|
||
|
{
|
||
|
Vector3 position;
|
||
|
Vector3 rayPos = Vector3.zero;
|
||
|
|
||
|
string name1, name2, name3, name4, name5;
|
||
|
|
||
|
RaycastHit hit;
|
||
|
|
||
|
// Inside Object Detection: Raycast all 5 sides from selected size to the probe.
|
||
|
// If all directions have the same name, the probe is inside an object.
|
||
|
// Down is not tested, so its easier to remove probes from objects with a hollow at bottom, like trees.
|
||
|
// Removing from the end of the list to the beginning
|
||
|
for (int i = probePositions.Count - 1; i >= 0; i--)
|
||
|
{
|
||
|
position = transform.TransformPoint(probePositions[i]);
|
||
|
|
||
|
name1 = "1";
|
||
|
name2 = "2";
|
||
|
name3 = "3";
|
||
|
name4 = "4";
|
||
|
name5 = "5";
|
||
|
|
||
|
// Up to probe
|
||
|
rayPos.Set(position.x, position.y + rayTestSizeInsideObject, position.z);
|
||
|
if (Physics.Raycast(rayPos, Vector3.down, out hit, Vector3.Distance(rayPos, position)))
|
||
|
name1 = hit.transform.name;
|
||
|
Debug.DrawLine(position, rayPos, Color.yellow, 1);
|
||
|
|
||
|
// Right to Probe
|
||
|
rayPos.Set(position.x + rayTestSizeInsideObject, position.y, position.z);
|
||
|
if (Physics.Raycast(rayPos, Vector3.left, out hit, Vector3.Distance(rayPos, position)))
|
||
|
name2 = hit.transform.name;
|
||
|
Debug.DrawLine(position, rayPos, Color.yellow, 1);
|
||
|
|
||
|
// Left to Probe
|
||
|
rayPos.Set(position.x - rayTestSizeInsideObject, position.y, position.z);
|
||
|
if (Physics.Raycast(rayPos, Vector3.right, out hit, Vector3.Distance(rayPos, position)))
|
||
|
name3 = hit.transform.name;
|
||
|
Debug.DrawLine(position, rayPos, Color.yellow, 1);
|
||
|
|
||
|
// Forward to Probe
|
||
|
rayPos.Set(position.x, position.y, position.z + rayTestSizeInsideObject);
|
||
|
if (Physics.Raycast(rayPos, Vector3.back, out hit, Vector3.Distance(rayPos, position)))
|
||
|
name4 = hit.transform.name;
|
||
|
Debug.DrawLine(position, rayPos, Color.yellow, 1);
|
||
|
|
||
|
// Back to Probe
|
||
|
rayPos.Set(position.x, position.y, position.z - rayTestSizeInsideObject);
|
||
|
if (Physics.Raycast(rayPos, Vector3.forward, out hit, Vector3.Distance(rayPos, position)))
|
||
|
name5 = hit.transform.name;
|
||
|
Debug.DrawLine(position, rayPos, Color.yellow, 1);
|
||
|
|
||
|
if (name1 == name2 &&
|
||
|
name1 == name3 &&
|
||
|
name1 == name4 &&
|
||
|
name1 == name5 &&
|
||
|
(hit.collider.gameObject.isStatic || !onlyStatic))
|
||
|
probePositions.RemoveAt(i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void CutFarFromObject()
|
||
|
{
|
||
|
Vector3 position;
|
||
|
Vector3 edge = Vector3.zero;
|
||
|
|
||
|
bool hitObject;
|
||
|
|
||
|
// Raycast all axis from one side to center, and vice versa.
|
||
|
// If there's at least one hit, the probe is near an object and will not be cut
|
||
|
for (int i = probePositions.Count - 1; i >= 0; i--)
|
||
|
{
|
||
|
// Scaling from relative to world position
|
||
|
position = transform.TransformPoint(probePositions[i]);
|
||
|
|
||
|
hitObject = false;
|
||
|
|
||
|
// Probe to down
|
||
|
edge.Set(position.x, position.y - rayTestSizeFarObject, position.z);
|
||
|
hitObject = hitObject || TestCenterEdge(position, edge);
|
||
|
|
||
|
// Probe to up
|
||
|
edge.Set(position.x, position.y + rayTestSizeFarObject, position.z);
|
||
|
hitObject = hitObject || TestCenterEdge(position, edge);
|
||
|
|
||
|
// Probe to left
|
||
|
edge.Set(position.x - rayTestSizeFarObject, position.y, position.z);
|
||
|
hitObject = hitObject || TestCenterEdge(position, edge);
|
||
|
|
||
|
// Probe to right
|
||
|
edge.Set(position.x + rayTestSizeFarObject, position.y, position.z);
|
||
|
hitObject = hitObject || TestCenterEdge(position, edge);
|
||
|
|
||
|
// Probe to Back
|
||
|
edge.Set(position.x, position.y, position.z - rayTestSizeFarObject);
|
||
|
hitObject = hitObject || TestCenterEdge(position, edge);
|
||
|
|
||
|
// Probe to Forward
|
||
|
edge.Set(position.x, position.y, position.z + rayTestSizeFarObject);
|
||
|
hitObject = hitObject || TestCenterEdge(position, edge);
|
||
|
|
||
|
//If probe hit nothing, remove
|
||
|
if (!hitObject) probePositions.RemoveAt(i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private bool TestCenterEdge(Vector3 center, Vector3 edge)
|
||
|
{
|
||
|
RaycastHit hit;
|
||
|
bool hitTest;
|
||
|
|
||
|
//from center to edge
|
||
|
hitTest = Physics.Raycast(center, (edge - center), out hit, Vector3.Distance(center, edge));
|
||
|
//if is not a static object and the plugin is set to ignore non static, its a false hit
|
||
|
hitTest = hitTest && (hit.collider.gameObject.isStatic || !onlyStatic);
|
||
|
|
||
|
//from edge to center
|
||
|
hitTest = hitTest || Physics.Raycast(edge, (center - edge), out hit, Vector3.Distance(edge, center));
|
||
|
//if is not a static object and the plugin is set to ignore non static, its a false hit
|
||
|
hitTest = hitTest && (hit.collider.gameObject.isStatic || !onlyStatic);
|
||
|
|
||
|
Debug.DrawLine(center, edge, Color.yellow, 1);
|
||
|
return hitTest;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
}
|