您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
159 行
7.0 KiB
159 行
7.0 KiB
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
using System.Collections;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
|
|
[ExecuteInEditMode]
|
|
[RequireComponent(typeof(BoxCollider))]
|
|
public class LightProbesVolumeSettings : MonoBehaviour
|
|
{
|
|
public float horizontalSpacing = 2.0f;
|
|
public float verticalSpacing = 2.0f;
|
|
public float OffsetFomFloor = 0.5f;
|
|
public int numberOfLayers = 2;
|
|
public bool FillVolume = false;
|
|
public bool FollowFloor = true;
|
|
public bool discardInsideGeometry;
|
|
public bool drawDebug = false;
|
|
|
|
private void OnEnable()
|
|
{
|
|
var boxCollider = GetComponent<BoxCollider>();
|
|
boxCollider.isTrigger = true;
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
public void Populate()
|
|
{
|
|
//avoid division by 0
|
|
horizontalSpacing = Mathf.Max(horizontalSpacing, 0.01f);
|
|
verticalSpacing = Mathf.Max(horizontalSpacing, 0.01f);
|
|
|
|
Collider col = gameObject.GetComponent<Collider>();
|
|
if (col == null) Debug.Log("Col not found", col);
|
|
|
|
//Check if there is already a lightprobegroup component
|
|
// if there is destroy it
|
|
LightProbeGroup oldLightprobes = gameObject.GetComponent<LightProbeGroup>();
|
|
if (oldLightprobes != null)
|
|
DestroyImmediate(oldLightprobes);
|
|
|
|
// Get the col bounds
|
|
Bounds bbox = col.bounds;
|
|
gameObject.GetComponent<BoxCollider>().enabled = false;
|
|
|
|
//Store bounds
|
|
|
|
float minX = bbox.min.x;
|
|
float minY = bbox.min.y;
|
|
float minZ = bbox.min.z;
|
|
float maxX = bbox.max.x;
|
|
float maxY = bbox.max.y;
|
|
float maxZ = bbox.max.z;
|
|
|
|
// Now go through in a grid and attempt to place a light probe using raycasting
|
|
float xCount = (maxX - minX)/horizontalSpacing;
|
|
float zCount = (maxZ - minZ) / horizontalSpacing;
|
|
float ycount = (maxY - minY) / verticalSpacing;
|
|
float startxoffset = ((maxX - minX) - Mathf.FloorToInt(xCount) * horizontalSpacing) / 2;
|
|
float startzoffset = ((maxZ - minZ) - Mathf.FloorToInt(zCount) * horizontalSpacing) / 2;
|
|
|
|
//if lightprobe count fits exactly in bounds, I know the probes at the maximum bounds will be rejected, so add offset
|
|
if (startxoffset == 0)
|
|
startxoffset = horizontalSpacing / 2;
|
|
if (startzoffset == 0)
|
|
startzoffset = horizontalSpacing / 2;
|
|
|
|
List<Vector3> VertPositions = new List<Vector3>();
|
|
|
|
for (int z = 0; z < zCount; z++)
|
|
{
|
|
for (int x = 0; x < xCount; x++)
|
|
{
|
|
//RaycastHit hit;
|
|
RaycastHit[] hits;
|
|
Ray ray = new Ray();
|
|
ray.origin = new Vector3(startxoffset + minX + x * horizontalSpacing, maxY + 1, startzoffset + minZ + z * horizontalSpacing);
|
|
ray.direction = -Vector3.up;
|
|
//if (Physics.Raycast(ray, out hit, (maxY - minY) * 2,-1,QueryTriggerInteraction.Ignore))
|
|
hits = Physics.RaycastAll(ray, (maxY - minY) * 2, -1, QueryTriggerInteraction.Ignore);
|
|
foreach(var hit in hits)
|
|
{
|
|
if (!hit.collider.gameObject.isStatic)
|
|
break;
|
|
if (hit.point.y + OffsetFomFloor < maxY && hit.point.y + OffsetFomFloor > minY)
|
|
VertPositions.Add(hit.point + new Vector3(0, OffsetFomFloor, 0));
|
|
if(drawDebug)
|
|
Debug.DrawRay(hit.point, -ray.direction * hit.distance, Color.red, (maxY - minY));
|
|
|
|
int maxLayer = FillVolume ? Mathf.FloorToInt(ycount) : numberOfLayers ;
|
|
|
|
for (int i = 1; i < maxLayer; i++)
|
|
{
|
|
if (hit.point.y + OffsetFomFloor + i * verticalSpacing < maxY && hit.point.y + OffsetFomFloor + verticalSpacing > minY)
|
|
VertPositions.Add(hit.point + new Vector3(0, OffsetFomFloor + i * verticalSpacing, 0));
|
|
}
|
|
EditorUtility.DisplayProgressBar("Tracing floor collisions", (z * x).ToString() + "/" + (zCount * xCount).ToString(), (float)(z * x) / (float)(zCount * xCount));
|
|
}
|
|
}
|
|
}
|
|
EditorUtility.ClearProgressBar();
|
|
List<Vector3> validVertPositions = new List<Vector3>();
|
|
|
|
int j = 0;
|
|
if (discardInsideGeometry)
|
|
{
|
|
Vector3 insideTestPosition = gameObject.transform.position + gameObject.GetComponent<BoxCollider>().center + new Vector3(0,maxY/2,0);
|
|
if(drawDebug)
|
|
{
|
|
Debug.DrawLine(insideTestPosition + Vector3.up, insideTestPosition - Vector3.up, Color.green, 5);
|
|
Debug.DrawLine(insideTestPosition + Vector3.right, insideTestPosition - Vector3.right, Color.green, 5);
|
|
Debug.DrawLine(insideTestPosition + Vector3.forward, insideTestPosition - Vector3.forward, Color.green, 5);
|
|
}
|
|
foreach (Vector3 positionCandidate in VertPositions)
|
|
{
|
|
EditorUtility.DisplayProgressBar("Checking probes inside geometry", j.ToString() + "/" + VertPositions.Count, (float)j / (float)VertPositions.Count);
|
|
|
|
Ray forwardRay = new Ray(insideTestPosition, Vector3.Normalize(positionCandidate - insideTestPosition));
|
|
Ray backwardRay = new Ray(positionCandidate, Vector3.Normalize(insideTestPosition - positionCandidate));
|
|
RaycastHit[] hitsForward;
|
|
RaycastHit[] hitsBackward;
|
|
hitsForward = Physics.RaycastAll(forwardRay,Vector3.Distance(positionCandidate,insideTestPosition),-1,QueryTriggerInteraction.Ignore);
|
|
hitsBackward = Physics.RaycastAll(backwardRay, Vector3.Distance(positionCandidate, insideTestPosition), -1, QueryTriggerInteraction.Ignore);
|
|
if (hitsForward.Length == hitsBackward.Length) validVertPositions.Add(positionCandidate);
|
|
else if (drawDebug)
|
|
Debug.DrawRay(backwardRay.origin, backwardRay.direction * Vector3.Distance(positionCandidate, insideTestPosition), Color.red, 5);
|
|
j++;
|
|
}
|
|
EditorUtility.ClearProgressBar();
|
|
}
|
|
else
|
|
validVertPositions = VertPositions;
|
|
|
|
|
|
// Check if we have any hits
|
|
if (validVertPositions.Count < 1)
|
|
{
|
|
Debug.Log("no valid hit for "+ gameObject.name);
|
|
gameObject.GetComponent<BoxCollider>().enabled = true;
|
|
return;
|
|
}
|
|
|
|
LightProbeGroup LPGroup = gameObject.AddComponent<LightProbeGroup>();
|
|
|
|
// Create lightprobe positions
|
|
Vector3[] ProbePos = new Vector3[validVertPositions.Count];
|
|
for (int i = 0; i < validVertPositions.Count; i++)
|
|
{
|
|
ProbePos[i] = gameObject.transform.InverseTransformPoint(validVertPositions[i]);
|
|
}
|
|
|
|
// Set new light probes
|
|
LPGroup.probePositions = ProbePos;
|
|
gameObject.GetComponent<BoxCollider>().enabled = true;
|
|
Debug.Log("Finished placing " + ProbePos.Length + " probes for " + gameObject.name);
|
|
}
|
|
#endif
|
|
}
|