1
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "AdvancedCullingSystem.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:37151e2099022af42afa90e2ee1b768a",
|
||||
"GUID:d8b63aba1907145bea998dd612889d6b",
|
||||
"GUID:e0cd26848372d4e5c891c569017e11f1",
|
||||
"GUID:2665a8d13d1b3f18800f46e256720795"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AdvancedCullingSystem
|
||||
{
|
||||
public class ChunkMark : MonoBehaviour
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,485 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditorInternal;
|
||||
|
||||
namespace AdvancedCullingSystem.ChunksMaster
|
||||
{
|
||||
public class ChunksMaster
|
||||
{
|
||||
private int _uvChannelsCount = 8;
|
||||
|
||||
private List<Mesh> _meshes;
|
||||
private List<List<Bounds>> _bounds;
|
||||
private List<List<Mesh>> _chunks;
|
||||
private List<int> _maxTriangles;
|
||||
|
||||
public List<Mesh> meshes
|
||||
{
|
||||
get
|
||||
{
|
||||
return _meshes;
|
||||
}
|
||||
}
|
||||
public List<List<Bounds>> bounds
|
||||
{
|
||||
get
|
||||
{
|
||||
return _bounds;
|
||||
}
|
||||
}
|
||||
public List<int> maxTriangles
|
||||
{
|
||||
get
|
||||
{
|
||||
return _maxTriangles;
|
||||
}
|
||||
}
|
||||
|
||||
private string _saveFolder;
|
||||
|
||||
|
||||
public ChunksMaster()
|
||||
{
|
||||
_meshes = new List<Mesh>();
|
||||
_bounds = new List<List<Bounds>>();
|
||||
_chunks = new List<List<Mesh>>();
|
||||
_maxTriangles = new List<int>();
|
||||
}
|
||||
|
||||
public void CreateChunksBounds(Mesh mesh, int maxTriangles)
|
||||
{
|
||||
int index = _meshes.IndexOf(mesh);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
if (_maxTriangles[index] == maxTriangles && _bounds[index].Count > 0)
|
||||
return;
|
||||
|
||||
_bounds[index].Clear();
|
||||
_maxTriangles[index] = maxTriangles;
|
||||
}
|
||||
else
|
||||
{
|
||||
_meshes.Add(mesh);
|
||||
_bounds.Add(new List<Bounds>());
|
||||
_chunks.Add(new List<Mesh>());
|
||||
_maxTriangles.Add(maxTriangles);
|
||||
}
|
||||
|
||||
ProcessChunk(mesh, GetTriangles(mesh), mesh.bounds, maxTriangles, true, false);
|
||||
}
|
||||
|
||||
public void CreateChunks(Mesh mesh, int maxTriangles, string saveFolder)
|
||||
{
|
||||
_saveFolder = saveFolder;
|
||||
|
||||
int index = _meshes.IndexOf(mesh);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
if (_maxTriangles[index] == maxTriangles && _chunks[index].Count > 0 && _chunks[0] != null)
|
||||
return;
|
||||
|
||||
_bounds[index].Clear();
|
||||
_chunks[index].Clear();
|
||||
|
||||
_maxTriangles[index] = maxTriangles;
|
||||
}
|
||||
else
|
||||
{
|
||||
_meshes.Add(mesh);
|
||||
_bounds.Add(new List<Bounds>());
|
||||
_chunks.Add(new List<Mesh>());
|
||||
_maxTriangles.Add(maxTriangles);
|
||||
}
|
||||
|
||||
if (!Directory.Exists(saveFolder))
|
||||
Directory.CreateDirectory(saveFolder);
|
||||
|
||||
ProcessChunk(mesh, GetTriangles(mesh), mesh.bounds, maxTriangles, true, true);
|
||||
}
|
||||
|
||||
public List<GameObject> SetupChunks(MeshFilter filter)
|
||||
{
|
||||
int index = _meshes.IndexOf(filter.sharedMesh);
|
||||
|
||||
if (index < 0)
|
||||
return null;
|
||||
|
||||
List<Mesh> chunks = _chunks[index];
|
||||
List<GameObject> chunksObjects = new List<GameObject>();
|
||||
|
||||
for (int i = 0; i < chunks.Count; i++)
|
||||
{
|
||||
GameObject chunkObject = new GameObject(filter.gameObject.name + "_chunk");
|
||||
|
||||
ComponentUtility.CopyComponent(filter);
|
||||
ComponentUtility.PasteComponentAsNew(chunkObject);
|
||||
|
||||
ComponentUtility.CopyComponent(filter.GetComponent<MeshRenderer>());
|
||||
ComponentUtility.PasteComponentAsNew(chunkObject);
|
||||
|
||||
chunkObject.transform.parent = filter.transform;
|
||||
|
||||
chunkObject.transform.localPosition = Vector3.zero;
|
||||
chunkObject.transform.localRotation = Quaternion.identity;
|
||||
chunkObject.transform.localScale = Vector3.one;
|
||||
|
||||
chunkObject.GetComponent<MeshFilter>().sharedMesh = chunks[i];
|
||||
chunkObject.AddComponent<ChunkMark>();
|
||||
|
||||
chunkObject.isStatic = filter.gameObject.isStatic;
|
||||
|
||||
chunksObjects.Add(chunkObject);
|
||||
}
|
||||
|
||||
filter.GetComponent<MeshRenderer>().enabled = false;
|
||||
|
||||
return chunksObjects;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_meshes.Clear();
|
||||
_bounds.Clear();
|
||||
_chunks.Clear();
|
||||
_maxTriangles.Clear();
|
||||
}
|
||||
|
||||
|
||||
private void ProcessChunk(Mesh mesh, List<int>[] triangles, Bounds bounds, int maxTriangles,
|
||||
bool createBounds, bool createChunks)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < triangles.Length; i++)
|
||||
count += triangles[i].Count / 3;
|
||||
|
||||
if (count < maxTriangles)
|
||||
{
|
||||
if(createBounds)
|
||||
_bounds[_meshes.IndexOf(mesh)].Add(bounds);
|
||||
|
||||
if (createChunks)
|
||||
CreateAndSaveMesh(mesh, triangles);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 size = bounds.size;
|
||||
|
||||
if (bounds.size.x >= bounds.size.y && bounds.size.x >= bounds.size.z)
|
||||
size.x /= 2;
|
||||
|
||||
else if (bounds.size.y >= bounds.size.x && bounds.size.y >= bounds.size.z)
|
||||
size.y /= 2;
|
||||
|
||||
else
|
||||
size.z /= 2;
|
||||
|
||||
Bounds leftBounds = new Bounds(bounds.min + size / 2, size);
|
||||
Bounds rightBounds = new Bounds(bounds.max - size / 2, size);
|
||||
|
||||
Vector3[] vertices = mesh.vertices;
|
||||
|
||||
List<int>[] leftTriangles = new List<int>[triangles.Length];
|
||||
List<int>[] rightTriangles = new List<int>[triangles.Length];
|
||||
|
||||
for (int i = 0; i < triangles.Length; i++)
|
||||
{
|
||||
leftTriangles[i] = new List<int>();
|
||||
rightTriangles[i] = new List<int>();
|
||||
|
||||
for (int c = 0; c < triangles[i].Count; c += 3)
|
||||
{
|
||||
Vector3 vec1 = vertices[triangles[i][c]];
|
||||
Vector3 vec2 = vertices[triangles[i][c + 1]];
|
||||
Vector3 vec3 = vertices[triangles[i][c + 2]];
|
||||
|
||||
if (leftBounds.Contains(vec1) || leftBounds.Contains(vec2) || leftBounds.Contains(vec3))
|
||||
{
|
||||
leftTriangles[i].Add(triangles[i][c]);
|
||||
leftTriangles[i].Add(triangles[i][c + 1]);
|
||||
leftTriangles[i].Add(triangles[i][c + 2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rightTriangles[i].Add(triangles[i][c]);
|
||||
rightTriangles[i].Add(triangles[i][c + 1]);
|
||||
rightTriangles[i].Add(triangles[i][c + 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProcessChunk(mesh, leftTriangles, leftBounds, maxTriangles, createBounds, createChunks);
|
||||
ProcessChunk(mesh, rightTriangles, rightBounds, maxTriangles, createBounds, createChunks);
|
||||
}
|
||||
|
||||
private List<int>[] GetTriangles(Mesh mesh)
|
||||
{
|
||||
int subMeshCount = mesh.subMeshCount;
|
||||
|
||||
List<int>[] triangles = new List<int>[subMeshCount];
|
||||
|
||||
for (int i = 0; i < subMeshCount; i++)
|
||||
triangles[i] = new List<int>(mesh.GetTriangles(i));
|
||||
|
||||
return triangles;
|
||||
}
|
||||
|
||||
private void GetUVs(Mesh mesh, out List<List<Vector2>> uvs, out List<int> uvChannels)
|
||||
{
|
||||
uvs = new List<List<Vector2>>();
|
||||
uvChannels = new List<int>();
|
||||
|
||||
for (int i = 0; i < _uvChannelsCount; i++)
|
||||
{
|
||||
List<Vector2> uv = new List<Vector2>();
|
||||
|
||||
mesh.GetUVs(i, uv);
|
||||
|
||||
if (uv != null && uv.Count > 0)
|
||||
{
|
||||
uvs.Add(uv);
|
||||
uvChannels.Add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateAndSaveMesh(Mesh src, List<int>[] triangles)
|
||||
{
|
||||
Mesh chunk = CreateChunkMesh(src, triangles);
|
||||
|
||||
string path = _saveFolder + chunk.GetHashCode() + ".asset";
|
||||
|
||||
AssetDatabase.CreateAsset(chunk, path);
|
||||
|
||||
_chunks[_meshes.IndexOf(src)].Add(AssetDatabase.LoadAssetAtPath<Mesh>(path));
|
||||
}
|
||||
|
||||
private Mesh CreateChunkMesh(Mesh src, List<int>[] triangles)
|
||||
{
|
||||
Mesh mesh = new Mesh();
|
||||
|
||||
GetUVs(src, out List<List<Vector2>> srcUvs, out List<int> uvChannels);
|
||||
|
||||
Vector3[] srcVertices = src.vertices;
|
||||
Vector4[] srcTangents = src.tangents;
|
||||
Vector3[] srcNormals = src.normals;
|
||||
Color[] srcColors = src.colors;
|
||||
Color32[] srcColors32 = src.colors32;
|
||||
|
||||
List<Vector3> vertices = new List<Vector3>();
|
||||
List<Vector4> tangents = new List<Vector4>();
|
||||
List<Vector3> normals = new List<Vector3>();
|
||||
List<Color> colors = new List<Color>();
|
||||
List<Color32> colors32 = new List<Color32>();
|
||||
List<Vector2>[] uvs = new List<Vector2>[uvChannels.Count];
|
||||
List<int>[] meshTriangles = new List<int>[triangles.Length];
|
||||
|
||||
for (int i = 0; i < uvs.Length; i++)
|
||||
uvs[i] = new List<Vector2>();
|
||||
|
||||
Dictionary<int, int> srcToNewTriangles = new Dictionary<int, int>();
|
||||
|
||||
for (int i = 0; i < triangles.Length; i++)
|
||||
{
|
||||
meshTriangles[i] = new List<int>();
|
||||
|
||||
for (int c = 0; c < triangles[i].Count; c++)
|
||||
{
|
||||
int srcTriangle = triangles[i][c];
|
||||
int newTriangle = -1;
|
||||
|
||||
if (srcToNewTriangles.ContainsKey(srcTriangle))
|
||||
{
|
||||
newTriangle = srcToNewTriangles[srcTriangle];
|
||||
}
|
||||
else
|
||||
{
|
||||
newTriangle = vertices.Count;
|
||||
|
||||
vertices.Add(srcVertices[srcTriangle]);
|
||||
tangents.Add(srcVertices[srcTriangle]);
|
||||
normals.Add(srcVertices[srcTriangle]);
|
||||
|
||||
for (int j = 0; j < uvChannels.Count; j++)
|
||||
uvs[j].Add(srcUvs[j][srcTriangle]);
|
||||
|
||||
if (srcColors.Length > 0)
|
||||
colors.Add(srcColors[srcTriangle]);
|
||||
|
||||
if (srcColors32.Length > 0)
|
||||
colors32.Add(srcColors32[srcTriangle]);
|
||||
|
||||
srcToNewTriangles.Add(srcTriangle, newTriangle);
|
||||
}
|
||||
|
||||
meshTriangles[i].Add(newTriangle);
|
||||
}
|
||||
}
|
||||
|
||||
mesh.vertices = vertices.ToArray();
|
||||
mesh.tangents = tangents.ToArray();
|
||||
mesh.normals = normals.ToArray();
|
||||
|
||||
if (colors.Count > 0)
|
||||
mesh.SetColors(colors);
|
||||
|
||||
if (colors32.Count > 0)
|
||||
mesh.SetColors(colors32);
|
||||
|
||||
for (int i = 0; i < uvChannels.Count; i++)
|
||||
mesh.SetUVs(uvChannels[i], uvs[i]);
|
||||
|
||||
mesh.subMeshCount = triangles.Length;
|
||||
|
||||
for (int i = 0; i < triangles.Length; i++)
|
||||
mesh.SetTriangles(meshTriangles[i], i);
|
||||
|
||||
mesh.RecalculateBounds();
|
||||
mesh.RecalculateNormals();
|
||||
mesh.RecalculateTangents();
|
||||
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class BoundsHelper
|
||||
{
|
||||
public static bool Intersects(this Bounds bounds, Vector3 t1, Vector3 t2, Vector3 t3)
|
||||
{
|
||||
float p0, p1, p2, r;
|
||||
|
||||
Vector3 extents = bounds.max - bounds.center;
|
||||
|
||||
Vector3 v0 = t1 - bounds.center,
|
||||
v1 = t2 - bounds.center,
|
||||
v2 = t3 - bounds.center;
|
||||
|
||||
Vector3 f0 = v1 - v0,
|
||||
f1 = v2 - v1,
|
||||
f2 = v0 - v2;
|
||||
|
||||
Vector3 a00 = new Vector3(0, -f0.z, f0.y),
|
||||
a01 = new Vector3(0, -f1.z, f1.y),
|
||||
a02 = new Vector3(0, -f2.z, f2.y),
|
||||
a10 = new Vector3(f0.z, 0, -f0.x),
|
||||
a11 = new Vector3(f1.z, 0, -f1.x),
|
||||
a12 = new Vector3(f2.z, 0, -f2.x),
|
||||
a20 = new Vector3(-f0.y, f0.x, 0),
|
||||
a21 = new Vector3(-f1.y, f1.x, 0),
|
||||
a22 = new Vector3(-f2.y, f2.x, 0);
|
||||
|
||||
// Test axis a00
|
||||
p0 = Vector3.Dot(v0, a00);
|
||||
p1 = Vector3.Dot(v1, a00);
|
||||
p2 = Vector3.Dot(v2, a00);
|
||||
r = extents.y * Mathf.Abs(f0.z) + extents.z * Mathf.Abs(f0.y);
|
||||
|
||||
if (Mathf.Max(-Mathf.Max(p0, p1, p2), Mathf.Min(p0, p1, p2)) > r)
|
||||
return false;
|
||||
|
||||
// Test axis a01
|
||||
p0 = Vector3.Dot(v0, a01);
|
||||
p1 = Vector3.Dot(v1, a01);
|
||||
p2 = Vector3.Dot(v2, a01);
|
||||
r = extents.y * Mathf.Abs(f1.z) + extents.z * Mathf.Abs(f1.y);
|
||||
|
||||
if (Mathf.Max(-Mathf.Max(p0, p1, p2), Mathf.Min(p0, p1, p2)) > r)
|
||||
return false;
|
||||
|
||||
// Test axis a02
|
||||
p0 = Vector3.Dot(v0, a02);
|
||||
p1 = Vector3.Dot(v1, a02);
|
||||
p2 = Vector3.Dot(v2, a02);
|
||||
r = extents.y * Mathf.Abs(f2.z) + extents.z * Mathf.Abs(f2.y);
|
||||
|
||||
if (Mathf.Max(-Mathf.Max(p0, p1, p2), Mathf.Min(p0, p1, p2)) > r)
|
||||
return false;
|
||||
|
||||
// Test axis a10
|
||||
p0 = Vector3.Dot(v0, a10);
|
||||
p1 = Vector3.Dot(v1, a10);
|
||||
p2 = Vector3.Dot(v2, a10);
|
||||
r = extents.x * Mathf.Abs(f0.z) + extents.z * Mathf.Abs(f0.x);
|
||||
if (Mathf.Max(-Mathf.Max(p0, p1, p2), Mathf.Min(p0, p1, p2)) > r)
|
||||
return false;
|
||||
|
||||
// Test axis a11
|
||||
p0 = Vector3.Dot(v0, a11);
|
||||
p1 = Vector3.Dot(v1, a11);
|
||||
p2 = Vector3.Dot(v2, a11);
|
||||
r = extents.x * Mathf.Abs(f1.z) + extents.z * Mathf.Abs(f1.x);
|
||||
|
||||
if (Mathf.Max(-Mathf.Max(p0, p1, p2), Mathf.Min(p0, p1, p2)) > r)
|
||||
return false;
|
||||
|
||||
// Test axis a12
|
||||
p0 = Vector3.Dot(v0, a12);
|
||||
p1 = Vector3.Dot(v1, a12);
|
||||
p2 = Vector3.Dot(v2, a12);
|
||||
r = extents.x * Mathf.Abs(f2.z) + extents.z * Mathf.Abs(f2.x);
|
||||
|
||||
if (Mathf.Max(-Mathf.Max(p0, p1, p2), Mathf.Min(p0, p1, p2)) > r)
|
||||
return false;
|
||||
|
||||
// Test axis a20
|
||||
p0 = Vector3.Dot(v0, a20);
|
||||
p1 = Vector3.Dot(v1, a20);
|
||||
p2 = Vector3.Dot(v2, a20);
|
||||
r = extents.x * Mathf.Abs(f0.y) + extents.y * Mathf.Abs(f0.x);
|
||||
|
||||
if (Mathf.Max(-Mathf.Max(p0, p1, p2), Mathf.Min(p0, p1, p2)) > r)
|
||||
return false;
|
||||
|
||||
// Test axis a21
|
||||
p0 = Vector3.Dot(v0, a21);
|
||||
p1 = Vector3.Dot(v1, a21);
|
||||
p2 = Vector3.Dot(v2, a21);
|
||||
r = extents.x * Mathf.Abs(f1.y) + extents.y * Mathf.Abs(f1.x);
|
||||
|
||||
if (Mathf.Max(-Mathf.Max(p0, p1, p2), Mathf.Min(p0, p1, p2)) > r)
|
||||
return false;
|
||||
|
||||
// Test axis a22
|
||||
p0 = Vector3.Dot(v0, a22);
|
||||
p1 = Vector3.Dot(v1, a22);
|
||||
p2 = Vector3.Dot(v2, a22);
|
||||
r = extents.x * Mathf.Abs(f2.y) + extents.y * Mathf.Abs(f2.x);
|
||||
|
||||
if (Mathf.Max(-Mathf.Max(p0, p1, p2), Mathf.Min(p0, p1, p2)) > r)
|
||||
return false;
|
||||
|
||||
if (Mathf.Max(v0.x, v1.x, v2.x) < -extents.x || Mathf.Min(v0.x, v1.x, v2.x) > extents.x)
|
||||
return false;
|
||||
|
||||
if (Mathf.Max(v0.y, v1.y, v2.y) < -extents.y || Mathf.Min(v0.y, v1.y, v2.y) > extents.y)
|
||||
return false;
|
||||
|
||||
if (Mathf.Max(v0.z, v1.z, v2.z) < -extents.z || Mathf.Min(v0.z, v1.z, v2.z) > extents.z)
|
||||
return false;
|
||||
|
||||
var normal = Vector3.Cross(f1, f0).normalized;
|
||||
var pl = new Plane(normal, Vector3.Dot(normal, t1));
|
||||
|
||||
return Intersects(bounds, pl);
|
||||
}
|
||||
|
||||
public static bool Intersects(this Bounds bounds, Plane plane)
|
||||
{
|
||||
Vector3 center = bounds.center;
|
||||
var extents = bounds.max - center;
|
||||
|
||||
var r = extents.x * Mathf.Abs(plane.normal.x) + extents.y * Mathf.Abs(plane.normal.y) + extents.z * Mathf.Abs(plane.normal.z);
|
||||
var s = Vector3.Dot(plane.normal, center) - plane.distance;
|
||||
|
||||
return Mathf.Abs(s) <= r;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,411 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEditor;
|
||||
|
||||
using Directory = System.IO.Directory;
|
||||
|
||||
namespace AdvancedCullingSystem.ChunksMaster
|
||||
{
|
||||
public class ChunksMasterEditorWindow : EditorWindow
|
||||
{
|
||||
public Vector2 size
|
||||
{
|
||||
get
|
||||
{
|
||||
return position.size;
|
||||
}
|
||||
}
|
||||
|
||||
private ChunksMaster _chunksMaster;
|
||||
|
||||
private string _dataSaveFolder;
|
||||
private int _maxTriangles = 10000;
|
||||
private bool _showChunks = true;
|
||||
private Vector2 _scrollPosition;
|
||||
private List<GameObject> _selectedObjects;
|
||||
|
||||
|
||||
[MenuItem("Tools/NGSTools/Advanced Culling System/Chunks Master")]
|
||||
private static void CreateWindow()
|
||||
{
|
||||
var window = GetWindow<ChunksMasterEditorWindow>(false, "Chunks Master", true);
|
||||
|
||||
window.minSize = new Vector2(490, 205);
|
||||
|
||||
window.Show();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
SceneView.duringSceneGui += OnSceneView;
|
||||
|
||||
_selectedObjects = new List<GameObject>();
|
||||
_chunksMaster = new ChunksMaster();
|
||||
|
||||
string scenePath = SceneManager.GetActiveScene().path;
|
||||
|
||||
_dataSaveFolder = (scenePath == null || scenePath == "") ? "ACSData/" :
|
||||
scenePath.Replace("Assets/", "").Replace(".unity", "_ACSData/");
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
CheckData();
|
||||
|
||||
GUILayout.BeginArea(new Rect(10, 10, size.x / 2 - 20, size.y - 70));
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
GUILayout.Label("Data Save Folder :", GUILayout.Width(110));
|
||||
|
||||
_dataSaveFolder = GUILayout.TextField(_dataSaveFolder);
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
_maxTriangles = Mathf.Max(EditorGUILayout.IntField("Max Triangles Per Chunk : ", _maxTriangles), 1000);
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
GUILayout.Label(_selectedObjects.Count > 0 ? "Selected Objects :" : "No objects selected");
|
||||
|
||||
_scrollPosition = GUILayout.BeginScrollView(_scrollPosition);
|
||||
|
||||
for (int i = 0; i < _selectedObjects.Count; i++)
|
||||
EditorGUILayout.ObjectField(_selectedObjects[i], typeof(GameObject), false);
|
||||
|
||||
GUILayout.EndScrollView();
|
||||
|
||||
GUILayout.EndArea();
|
||||
|
||||
|
||||
|
||||
GUILayout.BeginArea(new Rect(size.x / 2 + 10, 10, size.x / 2 - 20, size.y - 70));
|
||||
|
||||
if (GUILayout.Button("Add Static")) AddStatic();
|
||||
if (GUILayout.Button("Add Selected")) AddSelected();
|
||||
if (GUILayout.Button("Remove Selected")) RemoveSelected();
|
||||
if (GUILayout.Button("Remove All")) RemoveAll();
|
||||
|
||||
_showChunks = EditorGUILayout.ToggleLeft("Show Created Chunks", _showChunks);
|
||||
|
||||
GUILayout.EndArea();
|
||||
|
||||
|
||||
|
||||
GUILayout.BeginArea(new Rect(10, size.y - 50, size.x - 20, 40));
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
|
||||
if (IsSceneContainsChunks())
|
||||
if (GUILayout.Button("Delete Chunks", GUILayout.Width(100), GUILayout.Height(40)))
|
||||
DeleteChunks();
|
||||
|
||||
GUILayout.FlexibleSpace();
|
||||
|
||||
if (GUILayout.Button("Split", GUILayout.Width(70), GUILayout.Height(40))) Split();
|
||||
if (GUILayout.Button("Apply", GUILayout.Width(70), GUILayout.Height(40))) Apply();
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.EndArea();
|
||||
}
|
||||
|
||||
private void OnSceneView(SceneView sceneView)
|
||||
{
|
||||
if (!_showChunks)
|
||||
return;
|
||||
|
||||
CheckData();
|
||||
|
||||
Handles.color = Color.blue;
|
||||
|
||||
foreach (var go in _selectedObjects)
|
||||
{
|
||||
Mesh mesh = go.GetComponent<MeshFilter>().sharedMesh;
|
||||
|
||||
int index = _chunksMaster.meshes.IndexOf(mesh);
|
||||
|
||||
Handles.matrix = Matrix4x4.TRS(go.transform.position, go.transform.rotation, go.transform.lossyScale);
|
||||
|
||||
foreach (var bounds in _chunksMaster.bounds[index])
|
||||
Handles.DrawWireCube(bounds.center, bounds.size);
|
||||
}
|
||||
|
||||
Handles.matrix = Matrix4x4.identity;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
SceneView.duringSceneGui -= OnSceneView;
|
||||
}
|
||||
|
||||
|
||||
private void AddStatic()
|
||||
{
|
||||
int saveObjectsCount = _selectedObjects.Count;
|
||||
|
||||
|
||||
GameObject[] objects = FindObjectsOfType<Transform>()
|
||||
.Select(t => t.gameObject)
|
||||
.Where(go => go.isStatic)
|
||||
.ToArray();
|
||||
|
||||
for (int i = 0; i < objects.Length; i++)
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Adding static objects", i + " of " + objects.Length, (float)i / objects.Length);
|
||||
|
||||
if (IsValidGameObject(objects[i]))
|
||||
AddGameObject(objects[i]);
|
||||
}
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
|
||||
if ((_selectedObjects.Count - saveObjectsCount) == 0)
|
||||
Debug.Log("No new static objects added");
|
||||
|
||||
else
|
||||
Debug.Log("Added " + (_selectedObjects.Count - saveObjectsCount) + " objects");
|
||||
}
|
||||
|
||||
private void AddSelected()
|
||||
{
|
||||
int saveObjectsCount = _selectedObjects.Count;
|
||||
|
||||
|
||||
|
||||
GameObject[] selected = Selection.gameObjects;
|
||||
|
||||
if (selected == null || selected.Length == 0)
|
||||
{
|
||||
Debug.Log("No objects selected");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < selected.Length; i++)
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Adding selected objects", i + " of " + selected.Length, (float)i / selected.Length);
|
||||
|
||||
foreach (var go in selected[i].GetComponentsInChildren<Transform>().Select(t => t.gameObject))
|
||||
if (IsValidGameObject(go))
|
||||
AddGameObject(go);
|
||||
}
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
|
||||
if ((_selectedObjects.Count - saveObjectsCount) == 0)
|
||||
Debug.Log("No new objects added");
|
||||
|
||||
else
|
||||
Debug.Log("Added " + (_selectedObjects.Count - saveObjectsCount) + " objects");
|
||||
}
|
||||
|
||||
private void RemoveSelected()
|
||||
{
|
||||
int saveObjectsCount = _selectedObjects.Count;
|
||||
|
||||
|
||||
GameObject[] selected = Selection.gameObjects;
|
||||
|
||||
if (selected == null || selected.Length == 0)
|
||||
{
|
||||
Debug.Log("No objects selected");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < selected.Length; i++)
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Removing selected objects", i + " of " + selected.Length, (float)i / selected.Length);
|
||||
|
||||
foreach (var go in selected[i].GetComponentsInChildren<Transform>().Select(t => t.gameObject))
|
||||
if (_selectedObjects.Contains(go))
|
||||
_selectedObjects.Remove(go);
|
||||
}
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
|
||||
if ((saveObjectsCount - _selectedObjects.Count) == 0)
|
||||
Debug.Log("No objects removed");
|
||||
|
||||
else
|
||||
Debug.Log("Removed " + (saveObjectsCount - _selectedObjects.Count) + " objects");
|
||||
}
|
||||
|
||||
private void RemoveAll()
|
||||
{
|
||||
_selectedObjects.Clear();
|
||||
|
||||
Debug.Log("Removed all objects");
|
||||
}
|
||||
|
||||
private void Apply()
|
||||
{
|
||||
Mesh[] meshes = _selectedObjects.Select(go => go.GetComponent<MeshFilter>().sharedMesh).ToArray();
|
||||
|
||||
for (int i = 0; i < meshes.Length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Applying...", i + " of " + meshes.Length, (float)i / meshes.Length);
|
||||
|
||||
_chunksMaster.CreateChunksBounds(meshes[i], _maxTriangles);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.Log("Can't compute mesh " + meshes[i].name);
|
||||
Debug.Log("Cause : " + ex.Message + " " + ex.StackTrace);
|
||||
Debug.Log("Please write about it on e-mail(andre-orsk@yandex.ru) and I will help You");
|
||||
Debug.Log("-----------------------------------");
|
||||
}
|
||||
}
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
private void Split()
|
||||
{
|
||||
int count = _selectedObjects.Count;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Splitting...", i + " of " + count, (float)i / count);
|
||||
|
||||
MeshFilter filter = _selectedObjects[0].GetComponent<MeshFilter>();
|
||||
|
||||
_chunksMaster.CreateChunks(filter.sharedMesh, _maxTriangles,
|
||||
"Assets/" + _dataSaveFolder + filter.gameObject.name + "/");
|
||||
|
||||
_chunksMaster.SetupChunks(filter);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.Log("Can't split mesh " + _selectedObjects[0].name);
|
||||
Debug.Log("Cause : " + ex.Message + " " + ex.StackTrace);
|
||||
Debug.Log("Please write about it on e-mail(andre-orsk@yandex.ru) and I will help You");
|
||||
Debug.Log("-----------------------------------");
|
||||
}
|
||||
|
||||
_selectedObjects.RemoveAt(0);
|
||||
}
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
private void DeleteChunks()
|
||||
{
|
||||
ChunkMark[] chunks = FindObjectsOfType<ChunkMark>();
|
||||
for(int i = 0; i < chunks.Length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Deleting...", i + " of " + chunks.Length, (float)i / chunks.Length);
|
||||
|
||||
Mesh mesh = chunks[i].GetComponent<MeshFilter>().sharedMesh;
|
||||
|
||||
if (mesh != null)
|
||||
{
|
||||
string path = AssetDatabase.GetAssetPath(mesh);
|
||||
string parentFolder = path.Remove(path.LastIndexOf("/"), path.Length - path.LastIndexOf("/"));
|
||||
|
||||
if (path != null && path != "")
|
||||
AssetDatabase.DeleteAsset(path);
|
||||
|
||||
if (Directory.GetFiles(parentFolder).Length == 0)
|
||||
Directory.Delete(parentFolder, false);
|
||||
}
|
||||
|
||||
chunks[i].transform.parent.GetComponent<MeshRenderer>().enabled = true;
|
||||
|
||||
DestroyImmediate(chunks[i].gameObject);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.Log("Can't remove chunk " + chunks[i].name);
|
||||
Debug.Log("Cause : " + ex.Message + " " + ex.StackTrace);
|
||||
Debug.Log("Please write about it on e-mail(andre-orsk@yandex.ru) and I will help You");
|
||||
Debug.Log("-----------------------------------");
|
||||
}
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
|
||||
private void CheckData()
|
||||
{
|
||||
if (!_dataSaveFolder.EndsWith("/"))
|
||||
_dataSaveFolder += "/";
|
||||
|
||||
_selectedObjects = _selectedObjects.Where(obj => obj != null && IsValidGameObject(obj)).ToList();
|
||||
}
|
||||
|
||||
private bool IsSceneContainsChunks()
|
||||
{
|
||||
return FindObjectsOfType<ChunkMark>().Length > 0;
|
||||
}
|
||||
|
||||
private bool IsValidGameObject(GameObject go)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (go.GetComponent<MeshRenderer>() == null)
|
||||
return false;
|
||||
|
||||
MeshFilter filter = go.GetComponent<MeshFilter>();
|
||||
|
||||
if (filter == null || filter.sharedMesh == null)
|
||||
return false;
|
||||
|
||||
int subMeshCount = filter.sharedMesh.subMeshCount;
|
||||
|
||||
for (int i = 0; i < subMeshCount; i++)
|
||||
if ((filter.sharedMesh.GetTriangles(i).Length / 3) >= _maxTriangles)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.Log("Can't process " + go.name);
|
||||
Debug.Log("Cause : " + ex.Message + " " + ex.StackTrace);
|
||||
Debug.Log("Please write about it on e-mail(andre-orsk@yandex.ru) and I will help You");
|
||||
Debug.Log("-----------------------------------");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddGameObject(GameObject go)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_selectedObjects.Contains(go))
|
||||
{
|
||||
Mesh mesh = go.GetComponent<MeshFilter>().sharedMesh;
|
||||
|
||||
_chunksMaster.CreateChunksBounds(mesh, _maxTriangles);
|
||||
|
||||
_selectedObjects.Add(go);
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.Log("Can't add " + go.name);
|
||||
Debug.Log("Cause : " + ex.Message + " " + ex.StackTrace);
|
||||
Debug.Log("Please write about it on e-mail(andre-orsk@yandex.ru) and I will help You");
|
||||
Debug.Log("-----------------------------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,22 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem
|
||||
{
|
||||
public static class EditorHelper
|
||||
{
|
||||
public static void DrawSeparatorLine(float thickness, float padding)
|
||||
{
|
||||
Rect previousRect = GUILayoutUtility.GetLastRect();
|
||||
GUILayout.Space(padding);
|
||||
EditorGUILayout.LabelField("", GUILayout.Height(thickness));
|
||||
Rect lineRect = GUILayoutUtility.GetLastRect();
|
||||
lineRect.x = previousRect.x;
|
||||
lineRect.width = previousRect.width;
|
||||
EditorGUI.DrawRect(lineRect, Color.gray);
|
||||
GUILayout.Space(padding);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem
|
||||
{
|
||||
public static class LayersHelper
|
||||
{
|
||||
public static bool IsLayerExist(string name)
|
||||
{
|
||||
return LayerMask.NameToLayer(name) != -1;
|
||||
}
|
||||
|
||||
public static void CreateLayer(string name)
|
||||
{
|
||||
if (IsLayerExist(name))
|
||||
{
|
||||
Debug.Log("Layer " + name + " already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
|
||||
SerializedProperty layers = tagManager.FindProperty("layers");
|
||||
|
||||
for (int j = 8; j < layers.arraySize; j++)
|
||||
{
|
||||
SerializedProperty newLayer = layers.GetArrayElementAtIndex(j);
|
||||
|
||||
if (string.IsNullOrEmpty(newLayer.stringValue))
|
||||
{
|
||||
newLayer.stringValue = name;
|
||||
tagManager.ApplyModifiedProperties();
|
||||
Debug.Log("Layer created: " + name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogError("Failed to create layer: " + name + ", maximum number of layers reached.");
|
||||
}
|
||||
|
||||
public static void DisableCollisions(int layer)
|
||||
{
|
||||
SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
|
||||
|
||||
string[] layers = Enumerable.Range(0, 31)
|
||||
.Select(index => LayerMask.LayerToName(index))
|
||||
.Where(l => !string.IsNullOrEmpty(l))
|
||||
.ToArray();
|
||||
|
||||
for (int i = 0; i < layers.Length; i++)
|
||||
{
|
||||
int current = LayerMask.NameToLayer(layers[i]);
|
||||
|
||||
Physics.IgnoreLayerCollision(layer, current);
|
||||
Physics2D.IgnoreLayerCollision(layer, current);
|
||||
}
|
||||
|
||||
tagManager.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem
|
||||
{
|
||||
public static class SerializedObjectHelper
|
||||
{
|
||||
public static SerializedProperty FindAutoProperty(this SerializedObject obj, string name)
|
||||
{
|
||||
string path = string.Format("<{0}>k__BackingField", name);
|
||||
|
||||
return obj.FindProperty(path);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,213 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem.Dynamic
|
||||
{
|
||||
[CustomEditor(typeof(DC_Controller))]
|
||||
public class DC_ControllerEditor : Editor
|
||||
{
|
||||
private static Dictionary<int, DC_SelectionTool> _indexToSelection;
|
||||
|
||||
private static GUIStyle TitleLabelStyle;
|
||||
private static GUIStyle ButtonGUIStyle;
|
||||
|
||||
private new DC_Controller target
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.target as DC_Controller;
|
||||
}
|
||||
}
|
||||
private DC_SelectionTool _selectionTool;
|
||||
|
||||
private bool _containsReadyToBake;
|
||||
private bool _containsBaked;
|
||||
private bool _containsNonReadableMeshes;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
string layer = DC_Controller.GetCullingLayerName();
|
||||
|
||||
if (!LayersHelper.IsLayerExist(layer))
|
||||
{
|
||||
LayersHelper.CreateLayer(layer);
|
||||
LayersHelper.DisableCollisions(LayerMask.NameToLayer(layer));
|
||||
}
|
||||
|
||||
UpdateSelectionTool();
|
||||
UpdateSceneInfo();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (TitleLabelStyle == null)
|
||||
CreateGUIStyles();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Dynamic Culling", TitleLabelStyle);
|
||||
|
||||
EditorHelper.DrawSeparatorLine(1, 2);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
if (Application.isPlaying && target.MergeInGroups)
|
||||
{
|
||||
target.DrawGizmos = EditorGUILayout.Toggle("Draw Gizmos", target.DrawGizmos);
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
EditorGUI.BeginDisabledGroup(Application.isPlaying);
|
||||
|
||||
target.ControllerID = EditorGUILayout.IntField("Controller ID", target.ControllerID);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
UpdateSelectionTool();
|
||||
|
||||
target.ObjectsLifetime = EditorGUILayout.FloatField("Objects Lifetime", target.ObjectsLifetime);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
bool merge = EditorGUILayout.Toggle("Merge In Groups", target.MergeInGroups);
|
||||
float cellSize = target.CellSize;
|
||||
|
||||
if (target.MergeInGroups)
|
||||
cellSize = EditorGUILayout.FloatField("Cell Size", target.CellSize);
|
||||
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
target.MergeInGroups = merge;
|
||||
target.CellSize = cellSize;
|
||||
}
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
if (EditorGUI.EndChangeCheck() && !Application.isPlaying)
|
||||
EditorUtility.SetDirty(base.target);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (_selectionTool.Controller.gameObject != null)
|
||||
{
|
||||
bool sceneChanged = false;
|
||||
|
||||
_selectionTool.OnInspectorGUI(ref sceneChanged);
|
||||
|
||||
if (sceneChanged)
|
||||
UpdateSceneInfo();
|
||||
}
|
||||
|
||||
if (Application.isPlaying)
|
||||
return;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (_containsReadyToBake)
|
||||
{
|
||||
if (GUILayout.Button("Bake", ButtonGUIStyle))
|
||||
{
|
||||
DC_ControllerEditorUtil.BakeScene();
|
||||
UpdateSceneInfo();
|
||||
}
|
||||
}
|
||||
|
||||
if (_containsBaked)
|
||||
{
|
||||
if (GUILayout.Button("Clear", ButtonGUIStyle))
|
||||
{
|
||||
DC_ControllerEditorUtil.ClearBakedData();
|
||||
UpdateSceneInfo();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (_containsNonReadableMeshes)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Make Meshes Readable", ButtonGUIStyle))
|
||||
{
|
||||
DC_ControllerEditorUtil.MakeMeshesReadable();
|
||||
UpdateSceneInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void UpdateSelectionTool()
|
||||
{
|
||||
if (_indexToSelection == null)
|
||||
_indexToSelection = new Dictionary<int, DC_SelectionTool>();
|
||||
|
||||
if (!_indexToSelection.TryGetValue(target.ControllerID, out _selectionTool))
|
||||
{
|
||||
_selectionTool = new DC_SelectionTool(target);
|
||||
_indexToSelection.Add(target.ControllerID, _selectionTool);
|
||||
}
|
||||
|
||||
_selectionTool.Initialize(target, this);
|
||||
_selectionTool.Refresh();
|
||||
}
|
||||
|
||||
private void UpdateSceneInfo()
|
||||
{
|
||||
DC_SourceSettings[] settings = FindObjectsOfType<DC_SourceSettings>();
|
||||
|
||||
_containsReadyToBake = DC_ControllerEditorUtil.ContainsReadyToBakeSources(settings);
|
||||
_containsBaked = DC_ControllerEditorUtil.ContainsBakedSources(settings);
|
||||
_containsNonReadableMeshes = DC_ControllerEditorUtil.ContainsNonReadableMeshes(settings);
|
||||
}
|
||||
|
||||
private void CreateGUIStyles()
|
||||
{
|
||||
if (TitleLabelStyle == null)
|
||||
{
|
||||
TitleLabelStyle = new GUIStyle();
|
||||
TitleLabelStyle.fontSize = 24;
|
||||
TitleLabelStyle.fontStyle = FontStyle.Bold;
|
||||
TitleLabelStyle.alignment = TextAnchor.MiddleLeft;
|
||||
TitleLabelStyle.normal.textColor = Color.white;
|
||||
}
|
||||
|
||||
if (ButtonGUIStyle == null)
|
||||
{
|
||||
ButtonGUIStyle = new GUIStyle(GUI.skin.button);
|
||||
ButtonGUIStyle.fontSize = 12;
|
||||
ButtonGUIStyle.fixedHeight = 24;
|
||||
ButtonGUIStyle.margin = new RectOffset(5, 5, 5, 5);
|
||||
ButtonGUIStyle.border = new RectOffset(0, 0, 0, 0);
|
||||
ButtonGUIStyle.padding = new RectOffset(5, 5, 5, 5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[MenuItem("Tools/NGSTools/Advanced Culling System/Dynamic")]
|
||||
private static void CreateDynamicCulling()
|
||||
{
|
||||
GameObject go = new GameObject("Dynamic Culling");
|
||||
|
||||
go.AddComponent<DC_Controller>();
|
||||
|
||||
Selection.activeGameObject = go;
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.Selected | GizmoType.NonSelected)]
|
||||
private static void OnDrawGizmos(DC_Controller controller, GizmoType gizmoType)
|
||||
{
|
||||
if (_indexToSelection == null)
|
||||
_indexToSelection = new Dictionary<int, DC_SelectionTool>();
|
||||
|
||||
if (_indexToSelection.TryGetValue(controller.ControllerID, out DC_SelectionTool tool))
|
||||
tool.OnDrawGizmos();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem.Dynamic
|
||||
{
|
||||
public static class DC_ControllerEditorUtil
|
||||
{
|
||||
public static bool ContainsReadyToBakeSources(DC_SourceSettings[] sources)
|
||||
{
|
||||
foreach (var settings in sources)
|
||||
{
|
||||
if (!settings.IsIncompatible && !settings.ReadyForCulling)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ContainsBakedSources(DC_SourceSettings[] sources)
|
||||
{
|
||||
foreach (var settings in sources)
|
||||
{
|
||||
if (settings.ReadyForCulling)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ContainsNonReadableMeshes(DC_SourceSettings[] sources)
|
||||
{
|
||||
for (int i = 0; i < sources.Length; i++)
|
||||
{
|
||||
DC_SourceSettings source = sources[i];
|
||||
|
||||
if (source.SourceType == SourceType.SingleMesh)
|
||||
{
|
||||
if (source.TryGetComponent(out MeshFilter filter))
|
||||
{
|
||||
Mesh mesh = filter.sharedMesh;
|
||||
|
||||
if (mesh != null && !mesh.isReadable)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (MeshFilter filter in source.GetComponentsInChildren<MeshFilter>())
|
||||
{
|
||||
Mesh mesh = filter.sharedMesh;
|
||||
|
||||
if (mesh != null && !mesh.isReadable)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static void MakeMeshesReadable()
|
||||
{
|
||||
DC_SourceSettings[] sources = Object.FindObjectsOfType<DC_SourceSettings>();
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < sources.Length; i++)
|
||||
{
|
||||
DC_SourceSettings source = sources[i];
|
||||
|
||||
if (source.SourceType == SourceType.SingleMesh)
|
||||
{
|
||||
if (source.TryGetComponent(out MeshFilter filter))
|
||||
{
|
||||
if (filter.sharedMesh != null)
|
||||
if (MakeMeshReadable(filter.sharedMesh))
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (MeshFilter filter in source.GetComponentsInChildren<MeshFilter>())
|
||||
{
|
||||
if (filter.sharedMesh != null)
|
||||
if (MakeMeshReadable(filter.sharedMesh))
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log(count + " meshes maked readable");
|
||||
}
|
||||
|
||||
public static void BakeScene()
|
||||
{
|
||||
try
|
||||
{
|
||||
DC_SourceSettings[] sources = Object.FindObjectsOfType<DC_SourceSettings>();
|
||||
int count = sources.Length;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Bake...", i + " of " + count, (float)i / count);
|
||||
sources[i].Bake();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
}
|
||||
|
||||
public static void ClearBakedData()
|
||||
{
|
||||
try
|
||||
{
|
||||
DC_SourceSettings[] sources = Object.FindObjectsOfType<DC_SourceSettings>();
|
||||
int count = sources.Length;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("Clear...", i + " of " + count, (float)i / count);
|
||||
sources[i].ClearBakedData();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static bool MakeMeshReadable(Mesh mesh)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (mesh.isReadable)
|
||||
return false;
|
||||
|
||||
string path = AssetDatabase.GetAssetPath(mesh.GetInstanceID());
|
||||
|
||||
if (path == null || path == "")
|
||||
Debug.Log("Unable find path for mesh : " + mesh.name);
|
||||
|
||||
ModelImporter importer = (ModelImporter)AssetImporter.GetAtPath(path);
|
||||
|
||||
importer.isReadable = true;
|
||||
importer.SaveAndReimport();
|
||||
|
||||
Debug.Log(string.Format("Maked {0} mesh readable", mesh.name));
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.Log(string.Format("Unable to make mesh {0} readable. Reason : {1}{2}",
|
||||
mesh.name, ex.Message, ex.StackTrace));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem.Dynamic
|
||||
{
|
||||
public class DC_SelectionTool
|
||||
{
|
||||
public DC_Controller Controller { get; private set; }
|
||||
|
||||
private DC_BaseSelector[] _selectors;
|
||||
private DC_ControllerEditor _editor;
|
||||
|
||||
|
||||
public DC_SelectionTool(DC_Controller controller)
|
||||
{
|
||||
Controller = controller;
|
||||
|
||||
_selectors = new DC_BaseSelector[]
|
||||
{
|
||||
new DC_CamerasSelector(this),
|
||||
new DC_RenderersSelector(this),
|
||||
new DC_LODGroupsSelector(this),
|
||||
new DC_CustomSelector(this),
|
||||
new DC_OccludersSelector(this),
|
||||
new DC_IncompatiblesSelector(this)
|
||||
};
|
||||
}
|
||||
|
||||
public void Initialize(DC_Controller controller, DC_ControllerEditor editor)
|
||||
{
|
||||
Controller = controller;
|
||||
_editor = editor;
|
||||
}
|
||||
|
||||
public void OnInspectorGUI(ref bool sceneChanged)
|
||||
{
|
||||
for (int i = 0; i < _selectors.Length; i++)
|
||||
{
|
||||
if (_selectors[i].IsAvailable)
|
||||
_selectors[i].OnInspectorGUI(ref sceneChanged);
|
||||
}
|
||||
|
||||
if (sceneChanged) // || GUILayout.Button("Refresh"))
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public void OnDrawGizmos()
|
||||
{
|
||||
for (int i = 0; i < _selectors.Length; i++)
|
||||
{
|
||||
DC_BaseSelector selector = _selectors[i];
|
||||
|
||||
if (selector.IsAvailable)
|
||||
selector.OnDrawGizmos();
|
||||
}
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
for (int i = 0; i < _selectors.Length; i++)
|
||||
{
|
||||
DC_BaseSelector selector = _selectors[i];
|
||||
|
||||
if (selector.IsAvailable)
|
||||
selector.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void Repaint()
|
||||
{
|
||||
_editor?.Repaint();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,873 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.AnimatedValues;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem.Dynamic
|
||||
{
|
||||
public abstract class DC_BaseSelector
|
||||
{
|
||||
protected static GUIStyle FoldoutGUIStyle { get; private set; }
|
||||
protected static GUIStyle ButtonGUIStyle { get; private set; }
|
||||
protected static readonly Color GreenColor = new Color(0.3f, 1f, 0.3f, 1f);
|
||||
protected static readonly Color RedColor = new Color(1f, 0.3f, 0.3f, 1f);
|
||||
|
||||
public string Label { get; protected set; }
|
||||
public abstract bool IsAvailable { get; }
|
||||
|
||||
protected DC_Controller Controller
|
||||
{
|
||||
get
|
||||
{
|
||||
return _parent.Controller;
|
||||
}
|
||||
}
|
||||
|
||||
private DC_SelectionTool _parent;
|
||||
private AnimBool _foldout;
|
||||
|
||||
|
||||
public DC_BaseSelector(DC_SelectionTool parent)
|
||||
{
|
||||
Label = "Default Label";
|
||||
|
||||
_parent = parent;
|
||||
|
||||
_foldout = new AnimBool(false);
|
||||
_foldout.valueChanged.AddListener(parent.Repaint);
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public abstract void Refresh();
|
||||
|
||||
public virtual void OnInspectorGUI(ref bool sceneChanged)
|
||||
{
|
||||
if (FoldoutGUIStyle == null || ButtonGUIStyle == null)
|
||||
CreateGUIStyles();
|
||||
|
||||
_foldout.target = EditorGUILayout.Foldout(_foldout.target, Label, true, FoldoutGUIStyle);
|
||||
|
||||
if (EditorGUILayout.BeginFadeGroup(_foldout.faded))
|
||||
{
|
||||
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
|
||||
DrawContent(ref sceneChanged);
|
||||
}
|
||||
|
||||
EditorGUILayout.EndFadeGroup();
|
||||
|
||||
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
|
||||
}
|
||||
|
||||
public abstract void OnDrawGizmos();
|
||||
|
||||
|
||||
protected abstract void DrawContent(ref bool sceneChanged);
|
||||
|
||||
protected void DrawBounds(Bounds[] bounds, Color color)
|
||||
{
|
||||
Gizmos.color = color;
|
||||
for (int i = 0; i < bounds.Length; i++)
|
||||
Gizmos.DrawWireCube(bounds[i].center, bounds[i].size);
|
||||
}
|
||||
|
||||
private void CreateGUIStyles()
|
||||
{
|
||||
FoldoutGUIStyle = new GUIStyle(EditorStyles.foldout);
|
||||
FoldoutGUIStyle.fontSize = 15;
|
||||
FoldoutGUIStyle.fontStyle = FontStyle.Bold;
|
||||
FoldoutGUIStyle.normal.textColor = Color.white;
|
||||
|
||||
ButtonGUIStyle = new GUIStyle(GUI.skin.button);
|
||||
ButtonGUIStyle.fontSize = 12;
|
||||
ButtonGUIStyle.fixedHeight = 30;
|
||||
ButtonGUIStyle.margin = new RectOffset(5, 5, 5, 5);
|
||||
ButtonGUIStyle.border = new RectOffset(0, 0, 0, 0);
|
||||
ButtonGUIStyle.padding = new RectOffset(5, 5, 5, 5);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class DC_SelectorTemplate1 : DC_BaseSelector
|
||||
{
|
||||
protected DC_SelectorTemplate1(DC_SelectionTool parent)
|
||||
: base(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override void DrawContent(ref bool sceneChanged)
|
||||
{
|
||||
Color backColor = GUI.backgroundColor;
|
||||
bool picked = Selection.gameObjects.Length > 1 ||
|
||||
(Selection.gameObjects.Length == 1 && Selection.activeGameObject != Controller.gameObject);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
GUI.backgroundColor = GreenColor;
|
||||
if (GUILayout.Button("Assign Auto", ButtonGUIStyle))
|
||||
{
|
||||
AssignAuto();
|
||||
sceneChanged = true;
|
||||
}
|
||||
GUI.backgroundColor = backColor;
|
||||
|
||||
EditorGUI.BeginDisabledGroup(!picked);
|
||||
|
||||
if (GUILayout.Button("Assign Selected", ButtonGUIStyle))
|
||||
{
|
||||
AssignSelectedGameObjects();
|
||||
sceneChanged = true;
|
||||
}
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
if (!ShouldDrawClearOptions())
|
||||
{
|
||||
EditorGUILayout.EndHorizontal();
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
GUI.backgroundColor = RedColor;
|
||||
if (GUILayout.Button("Clear All", ButtonGUIStyle))
|
||||
{
|
||||
ClearAll();
|
||||
sceneChanged = true;
|
||||
}
|
||||
GUI.backgroundColor = backColor;
|
||||
|
||||
EditorGUI.BeginDisabledGroup(!picked);
|
||||
|
||||
if (GUILayout.Button("Clear Selected", ButtonGUIStyle))
|
||||
{
|
||||
ClearSelected();
|
||||
sceneChanged = true;
|
||||
}
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button("Select", ButtonGUIStyle))
|
||||
Select();
|
||||
}
|
||||
|
||||
|
||||
protected void AssignAuto()
|
||||
{
|
||||
GameObject[] gos = Object.FindObjectsOfType<GameObject>();
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < gos.Length; i++)
|
||||
{
|
||||
GameObject go = gos[i];
|
||||
|
||||
if (AssignIteration(go))
|
||||
count++;
|
||||
}
|
||||
|
||||
Debug.Log("Assigned " + count + " objects");
|
||||
}
|
||||
|
||||
protected void AssignSelectedGameObjects()
|
||||
{
|
||||
GameObject[] gos = Selection.gameObjects
|
||||
.SelectMany(go => go.GetComponentsInChildren<Transform>()
|
||||
.Select(t => t.gameObject))
|
||||
.ToArray();
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < gos.Length; i++)
|
||||
{
|
||||
GameObject go = gos[i];
|
||||
|
||||
if (AssignIteration(go))
|
||||
count++;
|
||||
}
|
||||
|
||||
Debug.Log("Assigned " + count + " objects");
|
||||
}
|
||||
|
||||
protected void ClearSelected()
|
||||
{
|
||||
GameObject[] gos = Selection.gameObjects
|
||||
.SelectMany(go => go.GetComponentsInChildren<Transform>()
|
||||
.Select(t => t.gameObject))
|
||||
.ToArray();
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < gos.Length; i++)
|
||||
{
|
||||
GameObject go = gos[i];
|
||||
|
||||
if (ClearIteration(go))
|
||||
count++;
|
||||
}
|
||||
|
||||
Debug.Log("Cleared " + count + " objects");
|
||||
}
|
||||
|
||||
|
||||
protected abstract bool ShouldDrawClearOptions();
|
||||
|
||||
protected abstract bool AssignIteration(GameObject current);
|
||||
|
||||
protected abstract bool ClearIteration(GameObject current);
|
||||
|
||||
protected abstract void ClearAll();
|
||||
|
||||
protected abstract void Select();
|
||||
}
|
||||
|
||||
public class DC_CamerasSelector : DC_SelectorTemplate1
|
||||
{
|
||||
public override bool IsAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
return !Application.isPlaying;
|
||||
}
|
||||
}
|
||||
private DC_Camera[] _cameras;
|
||||
|
||||
|
||||
public DC_CamerasSelector(DC_SelectionTool parent) : base(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
_cameras = Object.FindObjectsOfType<DC_Camera>();
|
||||
|
||||
Label = "Cameras (" + _cameras.Length + ")";
|
||||
}
|
||||
|
||||
public override void OnDrawGizmos()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected override bool ShouldDrawClearOptions()
|
||||
{
|
||||
return _cameras.Length > 0;
|
||||
}
|
||||
|
||||
protected override bool AssignIteration(GameObject current)
|
||||
{
|
||||
if (!current.activeInHierarchy)
|
||||
return false;
|
||||
|
||||
if (current.TryGetComponent(out DC_Camera cullingCamera))
|
||||
return false;
|
||||
|
||||
if (current.TryGetComponent(out Camera camera))
|
||||
{
|
||||
Controller.AddCamera(camera, 1500);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void ClearAll()
|
||||
{
|
||||
for (int i = 0; i < _cameras.Length; i++)
|
||||
{
|
||||
Object.DestroyImmediate(_cameras[i]);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ClearIteration(GameObject current)
|
||||
{
|
||||
if (current.TryGetComponent(out DC_Camera camera))
|
||||
{
|
||||
Object.DestroyImmediate(camera);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Select()
|
||||
{
|
||||
Selection.objects = _cameras.Select(c => c.gameObject).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public class DC_RenderersSelector : DC_SelectorTemplate1
|
||||
{
|
||||
public override bool IsAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
return !Application.isPlaying;
|
||||
}
|
||||
}
|
||||
|
||||
private DC_SourceSettings[] _renderersSettings;
|
||||
private Bounds[] _bounds;
|
||||
private bool _drawGizmos;
|
||||
|
||||
public DC_RenderersSelector(DC_SelectionTool parent)
|
||||
: base(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
_renderersSettings = Object.FindObjectsOfType<DC_SourceSettings>()
|
||||
.Where(s => s.SourceType == SourceType.SingleMesh && s.ControllerID == Controller.ControllerID)
|
||||
.ToArray();
|
||||
|
||||
Bounds bounds = default;
|
||||
_bounds = _renderersSettings
|
||||
.Where(s => s.TryGetBounds(ref bounds))
|
||||
.Select(r => bounds)
|
||||
.ToArray();
|
||||
|
||||
Label = "Renderers (" + _renderersSettings.Length + ")";
|
||||
}
|
||||
|
||||
protected override void DrawContent(ref bool sceneChanged)
|
||||
{
|
||||
_drawGizmos = EditorGUILayout.Toggle("Draw Gizmos", _drawGizmos);
|
||||
|
||||
base.DrawContent(ref sceneChanged);
|
||||
}
|
||||
|
||||
public override void OnDrawGizmos()
|
||||
{
|
||||
if (!_drawGizmos || _bounds == null)
|
||||
return;
|
||||
|
||||
DrawBounds(_bounds, Color.blue);
|
||||
}
|
||||
|
||||
|
||||
protected override bool ShouldDrawClearOptions()
|
||||
{
|
||||
return _renderersSettings.Length > 0;
|
||||
}
|
||||
|
||||
protected override bool AssignIteration(GameObject current)
|
||||
{
|
||||
if (!current.activeInHierarchy)
|
||||
return false;
|
||||
|
||||
if (current.GetComponent<DC_SourceSettings>() != null)
|
||||
return false;
|
||||
|
||||
if (current.GetComponent<DC_Occluder>() != null)
|
||||
return false;
|
||||
|
||||
MeshRenderer renderer = current.GetComponent<MeshRenderer>();
|
||||
|
||||
if (renderer == null || !renderer.enabled)
|
||||
return false;
|
||||
|
||||
LODGroup group = current.GetComponentInParent<LODGroup>();
|
||||
|
||||
if (group != null && group.GetLODs().ContainsAny(r => r == renderer))
|
||||
return false;
|
||||
|
||||
Controller.AddObjectForCulling(renderer).CheckCompatibility();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool ClearIteration(GameObject current)
|
||||
{
|
||||
if (current.TryGetComponent(out DC_SourceSettings settings))
|
||||
{
|
||||
if (settings.SourceType != SourceType.SingleMesh)
|
||||
return false;
|
||||
|
||||
if (settings.ControllerID != Controller.ControllerID)
|
||||
return false;
|
||||
|
||||
settings.ClearBakedData();
|
||||
|
||||
Object.DestroyImmediate(settings);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void ClearAll()
|
||||
{
|
||||
for (int i = 0; i < _renderersSettings.Length; i++)
|
||||
{
|
||||
_renderersSettings[i].ClearBakedData();
|
||||
|
||||
Object.DestroyImmediate(_renderersSettings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Select()
|
||||
{
|
||||
Selection.objects = _renderersSettings.Select(s => s.gameObject).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public class DC_LODGroupsSelector : DC_SelectorTemplate1
|
||||
{
|
||||
public override bool IsAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
return !Application.isPlaying;
|
||||
}
|
||||
}
|
||||
|
||||
private DC_SourceSettings[] _settings;
|
||||
private Bounds[] _bounds;
|
||||
private bool _drawGizmos;
|
||||
|
||||
public DC_LODGroupsSelector(DC_SelectionTool parent) : base(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
_settings = Object.FindObjectsOfType<DC_SourceSettings>()
|
||||
.Where(s => s.SourceType == SourceType.LODGroup && s.ControllerID == Controller.ControllerID)
|
||||
.ToArray();
|
||||
|
||||
Bounds bounds = default;
|
||||
_bounds = _settings
|
||||
.Where(s => s.TryGetBounds(ref bounds))
|
||||
.Select(r => bounds)
|
||||
.ToArray();
|
||||
|
||||
Label = "LODGroups (" + _settings.Length + ")";
|
||||
}
|
||||
|
||||
protected override void DrawContent(ref bool sceneChanged)
|
||||
{
|
||||
_drawGizmos = EditorGUILayout.Toggle("Draw Gizmos", _drawGizmos);
|
||||
|
||||
base.DrawContent(ref sceneChanged);
|
||||
}
|
||||
|
||||
public override void OnDrawGizmos()
|
||||
{
|
||||
if (!_drawGizmos || _bounds == null)
|
||||
return;
|
||||
|
||||
DrawBounds(_bounds, Color.yellow);
|
||||
}
|
||||
|
||||
|
||||
protected override bool ShouldDrawClearOptions()
|
||||
{
|
||||
return _settings.Length > 0;
|
||||
}
|
||||
|
||||
protected override bool AssignIteration(GameObject current)
|
||||
{
|
||||
if (!current.activeInHierarchy)
|
||||
return false;
|
||||
|
||||
if (current.GetComponent<DC_SourceSettings>() != null)
|
||||
return false;
|
||||
|
||||
if (current.GetComponent<DC_Occluder>() != null)
|
||||
return false;
|
||||
|
||||
LODGroup group = current.GetComponent<LODGroup>();
|
||||
|
||||
if (group == null)
|
||||
return false;
|
||||
|
||||
Controller.AddObjectForCulling(group).CheckCompatibility();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void ClearAll()
|
||||
{
|
||||
for (int i = 0; i < _settings.Length; i++)
|
||||
{
|
||||
_settings[i].ClearBakedData();
|
||||
|
||||
Object.DestroyImmediate(_settings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ClearIteration(GameObject current)
|
||||
{
|
||||
if (current.TryGetComponent(out DC_SourceSettings settings))
|
||||
{
|
||||
if (settings.SourceType != SourceType.LODGroup)
|
||||
return false;
|
||||
|
||||
if (settings.ControllerID != Controller.ControllerID)
|
||||
return false;
|
||||
|
||||
settings.ClearBakedData();
|
||||
|
||||
Object.DestroyImmediate(settings);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void Select()
|
||||
{
|
||||
Selection.objects = _settings.Select(s => s.gameObject).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public class DC_CustomSelector : DC_BaseSelector
|
||||
{
|
||||
public override bool IsAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
return !Application.isPlaying;
|
||||
}
|
||||
}
|
||||
|
||||
private DC_SourceSettings[] _customSettings;
|
||||
private Bounds[] _bounds;
|
||||
private bool _drawGizmos;
|
||||
|
||||
|
||||
public DC_CustomSelector(DC_SelectionTool parent) : base(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
_customSettings = Object.FindObjectsOfType<DC_SourceSettings>()
|
||||
.Where(s => s.SourceType == SourceType.Custom && s.ControllerID == Controller.ControllerID)
|
||||
.ToArray();
|
||||
|
||||
Bounds bounds = default;
|
||||
_bounds = _customSettings
|
||||
.Where(s => s.TryGetBounds(ref bounds))
|
||||
.Select(r => bounds)
|
||||
.ToArray();
|
||||
|
||||
Label = "Custom (" + _customSettings.Length + ")";
|
||||
}
|
||||
|
||||
protected override void DrawContent(ref bool sceneChanged)
|
||||
{
|
||||
_drawGizmos = EditorGUILayout.Toggle("Draw Gizmos", _drawGizmos);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (GUILayout.Button("Select", ButtonGUIStyle))
|
||||
Select();
|
||||
|
||||
Color backColor = GUI.backgroundColor;
|
||||
|
||||
GUI.backgroundColor = RedColor;
|
||||
if (GUILayout.Button("Clear All", ButtonGUIStyle))
|
||||
{
|
||||
ClearAll();
|
||||
sceneChanged = true;
|
||||
}
|
||||
GUI.backgroundColor = backColor;
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
public override void OnDrawGizmos()
|
||||
{
|
||||
if (!_drawGizmos || _bounds == null)
|
||||
return;
|
||||
|
||||
DrawBounds(_bounds, Color.white);
|
||||
}
|
||||
|
||||
|
||||
private void ClearAll()
|
||||
{
|
||||
for (int i = 0; i < _customSettings.Length; i++)
|
||||
Object.DestroyImmediate(_customSettings[i]);
|
||||
}
|
||||
|
||||
private void Select()
|
||||
{
|
||||
Selection.objects = _customSettings.Select(o => o.gameObject).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public class DC_OccludersSelector : DC_BaseSelector
|
||||
{
|
||||
public override bool IsAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
return !Application.isPlaying;
|
||||
}
|
||||
}
|
||||
|
||||
private DC_Occluder[] _occluders;
|
||||
private Bounds[] _bounds;
|
||||
private OccluderType _occluderType;
|
||||
private bool _drawGizmos;
|
||||
|
||||
|
||||
public DC_OccludersSelector(DC_SelectionTool parent) : base(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
_occluders = Object.FindObjectsOfType<DC_Occluder>();
|
||||
|
||||
Bounds bounds = default;
|
||||
_bounds = _occluders
|
||||
.Where(o => o.TryGetBounds(ref bounds))
|
||||
.Select(o => bounds)
|
||||
.ToArray();
|
||||
|
||||
Label = "Occluders (" + _occluders.Length + ")";
|
||||
}
|
||||
|
||||
protected override void DrawContent(ref bool sceneChanged)
|
||||
{
|
||||
_drawGizmos = EditorGUILayout.Toggle("Draw Gizmos", _drawGizmos);
|
||||
_occluderType = (OccluderType) EditorGUILayout.EnumPopup("Occluder Type", _occluderType);
|
||||
|
||||
Color backColor = GUI.backgroundColor;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
GUI.backgroundColor = GreenColor;
|
||||
if (GUILayout.Button("Assign Selected", ButtonGUIStyle))
|
||||
{
|
||||
AssignSelected();
|
||||
sceneChanged = true;
|
||||
}
|
||||
GUI.backgroundColor = backColor;
|
||||
|
||||
if (_occluders.Length == 0)
|
||||
{
|
||||
EditorGUILayout.EndHorizontal();
|
||||
return;
|
||||
}
|
||||
|
||||
GUI.backgroundColor = RedColor;
|
||||
if (GUILayout.Button("Clear Selected", ButtonGUIStyle))
|
||||
{
|
||||
ClearSelected();
|
||||
sceneChanged = true;
|
||||
}
|
||||
GUI.backgroundColor = backColor;
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button("Clear All", ButtonGUIStyle))
|
||||
{
|
||||
ClearAll();
|
||||
sceneChanged = true;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Select", ButtonGUIStyle))
|
||||
Select();
|
||||
}
|
||||
|
||||
public override void OnDrawGizmos()
|
||||
{
|
||||
if (!_drawGizmos || _bounds == null)
|
||||
return;
|
||||
|
||||
DrawBounds(_bounds, Color.green);
|
||||
}
|
||||
|
||||
|
||||
private void AssignSelected()
|
||||
{
|
||||
GameObject[] gos = Selection.gameObjects
|
||||
.SelectMany(go => go.GetComponentsInChildren<Transform>()
|
||||
.Select(t => t.gameObject))
|
||||
.ToArray();
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < gos.Length; i++)
|
||||
{
|
||||
GameObject go = gos[i];
|
||||
|
||||
if (go.TryGetComponent(out DC_SourceSettings settings))
|
||||
continue;
|
||||
|
||||
if (_occluderType == OccluderType.Collider)
|
||||
{
|
||||
if (go.GetComponent<Collider>() != null)
|
||||
{
|
||||
go.AddComponent<DC_Occluder>();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else if (_occluderType == OccluderType.Mesh)
|
||||
{
|
||||
if (go.GetComponent<MeshRenderer>() != null)
|
||||
{
|
||||
go.AddComponent<DC_Occluder>();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (go.GetComponent<LODGroup>() != null)
|
||||
{
|
||||
go.AddComponent<DC_Occluder>();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("Assigned " + count + " objects");
|
||||
}
|
||||
|
||||
private void ClearSelected()
|
||||
{
|
||||
GameObject[] gos = Selection.gameObjects
|
||||
.SelectMany(go => go.GetComponentsInChildren<Transform>()
|
||||
.Select(t => t.gameObject))
|
||||
.ToArray();
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < gos.Length; i++)
|
||||
{
|
||||
GameObject go = gos[i];
|
||||
|
||||
if (go.TryGetComponent(out DC_Occluder occluder))
|
||||
{
|
||||
Object.DestroyImmediate(occluder);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("Clear " + count + " objects");
|
||||
}
|
||||
|
||||
private void ClearAll()
|
||||
{
|
||||
for (int i = 0; i < _occluders.Length; i++)
|
||||
Object.DestroyImmediate(_occluders[i]);
|
||||
}
|
||||
|
||||
private void Select()
|
||||
{
|
||||
Selection.objects = _occluders.Select(o => o.gameObject).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public class DC_IncompatiblesSelector : DC_BaseSelector
|
||||
{
|
||||
public override bool IsAvailable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private DC_SourceSettings[] _settings;
|
||||
|
||||
public DC_IncompatiblesSelector(DC_SelectionTool parent)
|
||||
: base(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Refresh()
|
||||
{
|
||||
_settings = Object.FindObjectsOfType<DC_SourceSettings>()
|
||||
.Where(s => s.IsIncompatible)
|
||||
.ToArray();
|
||||
|
||||
Label = "Incompatible Sources (" + _settings.Length + ")";
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI(ref bool sceneChanged)
|
||||
{
|
||||
if (_settings.Length == 0)
|
||||
return;
|
||||
|
||||
base.OnInspectorGUI(ref sceneChanged);
|
||||
}
|
||||
|
||||
protected override void DrawContent(ref bool sceneChanged)
|
||||
{
|
||||
if (_settings.Length == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Incompatible sources not found :)", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Color back = GUI.backgroundColor;
|
||||
|
||||
GUI.backgroundColor = GreenColor;
|
||||
|
||||
if (GUILayout.Button("Clear All", ButtonGUIStyle))
|
||||
{
|
||||
ClearAll();
|
||||
sceneChanged = true;
|
||||
}
|
||||
|
||||
GUI.backgroundColor = back;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Select", ButtonGUIStyle))
|
||||
Select();
|
||||
|
||||
if (GUILayout.Button("Print", ButtonGUIStyle))
|
||||
Print();
|
||||
}
|
||||
|
||||
public override void OnDrawGizmos()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void ClearAll()
|
||||
{
|
||||
for (int i = 0; i < _settings.Length; i++)
|
||||
Object.DestroyImmediate(_settings[i]);
|
||||
}
|
||||
|
||||
private void Select()
|
||||
{
|
||||
Selection.objects = _settings.Select(o => o.gameObject).ToArray();
|
||||
}
|
||||
|
||||
private void Print()
|
||||
{
|
||||
for (int i = 0; i < _settings.Length; i++)
|
||||
Debug.Log(_settings[i].gameObject.name + " " + _settings[i].IncompatibilityReason);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,343 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem.Dynamic
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(DC_SourceSettings))]
|
||||
public class DC_SourceSettingsEditor : Editor
|
||||
{
|
||||
private new DC_SourceSettings target
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.target as DC_SourceSettings;
|
||||
}
|
||||
}
|
||||
|
||||
private SerializedProperty _controllerIdProp;
|
||||
private SerializedProperty _sourceTypeProp;
|
||||
private SerializedProperty _isIncompatibleProp;
|
||||
private SerializedProperty _incompatibilityReasonProp;
|
||||
private SourceSettingsStrategyEditor _strategyEditor;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_controllerIdProp = serializedObject.FindAutoProperty(nameof(target.ControllerID));
|
||||
_sourceTypeProp = serializedObject.FindProperty("_sourceType");
|
||||
_isIncompatibleProp = serializedObject.FindAutoProperty(nameof(target.IsIncompatible));
|
||||
_incompatibilityReasonProp = serializedObject.FindAutoProperty(nameof(target.IncompatibilityReason));
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
_strategyEditor = GetSourceSettingsStrategyEditor();
|
||||
_strategyEditor?.SetContext(serializedObject);
|
||||
|
||||
DrawHelpBox();
|
||||
|
||||
if (DrawProperties())
|
||||
ApplyModifiedProperties();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Check Compatibility"))
|
||||
CheckCompatibilities();
|
||||
}
|
||||
|
||||
private void OnSceneGUI()
|
||||
{
|
||||
_strategyEditor?.OnSceneGUI(target);
|
||||
}
|
||||
|
||||
|
||||
private SourceSettingsStrategyEditor GetSourceSettingsStrategyEditor()
|
||||
{
|
||||
if (!_sourceTypeProp.hasMultipleDifferentValues)
|
||||
{
|
||||
SourceType sourceType = (SourceType)_sourceTypeProp.enumValueIndex;
|
||||
|
||||
if (sourceType == SourceType.SingleMesh)
|
||||
{
|
||||
if (_strategyEditor is RendererSourceSettingsStrategyEditor)
|
||||
return _strategyEditor;
|
||||
|
||||
return new RendererSourceSettingsStrategyEditor();
|
||||
}
|
||||
|
||||
if (sourceType == SourceType.LODGroup)
|
||||
{
|
||||
if (_strategyEditor is LODGroupSourceSettingsStrategyEditor)
|
||||
return _strategyEditor;
|
||||
|
||||
return new LODGroupSourceSettingsStrategyEditor();
|
||||
}
|
||||
|
||||
if (sourceType == SourceType.Custom)
|
||||
{
|
||||
if (_strategyEditor is CustomSourceSettingsStrategyEditor)
|
||||
return _strategyEditor;
|
||||
|
||||
return new CustomSourceSettingsStrategyEditor();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void DrawHelpBox()
|
||||
{
|
||||
if (_isIncompatibleProp.boolValue && !_isIncompatibleProp.hasMultipleDifferentValues)
|
||||
{
|
||||
string text = _incompatibilityReasonProp.stringValue;
|
||||
|
||||
EditorGUILayout.HelpBox(text, MessageType.Warning);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
}
|
||||
|
||||
private bool DrawProperties()
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(Application.isPlaying);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
EditorGUILayout.PropertyField(_controllerIdProp);
|
||||
EditorGUILayout.PropertyField(_sourceTypeProp);
|
||||
|
||||
_strategyEditor?.DrawProperties();
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
return EditorGUI.EndChangeCheck();
|
||||
}
|
||||
|
||||
private void ApplyModifiedProperties()
|
||||
{
|
||||
_strategyEditor?.ApplyModifiedProperties(targets);
|
||||
|
||||
foreach (var target in targets)
|
||||
{
|
||||
DC_SourceSettings current = target as DC_SourceSettings;
|
||||
|
||||
if (!_controllerIdProp.hasMultipleDifferentValues)
|
||||
current.ControllerID = _controllerIdProp.intValue;
|
||||
|
||||
if (!_sourceTypeProp.hasMultipleDifferentValues)
|
||||
current.SourceType = (SourceType) _sourceTypeProp.enumValueIndex;
|
||||
|
||||
EditorUtility.SetDirty(target);
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckCompatibilities()
|
||||
{
|
||||
foreach (var target in targets)
|
||||
{
|
||||
DC_SourceSettings current = target as DC_SourceSettings;
|
||||
|
||||
if (current.CheckCompatibility())
|
||||
{
|
||||
Debug.Log(current.name + " is compatible!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log(current.name + " is incompatible. Reason : " + current.IncompatibilityReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private abstract class SourceSettingsStrategyEditor
|
||||
{
|
||||
protected SerializedObject Context { get; private set; }
|
||||
private bool _propertiesChanged;
|
||||
|
||||
|
||||
public void SetContext(SerializedObject context)
|
||||
{
|
||||
Context = context;
|
||||
OnContextSet();
|
||||
}
|
||||
|
||||
public void DrawProperties()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
DrawPropertiesInternal();
|
||||
|
||||
_propertiesChanged = EditorGUI.EndChangeCheck();
|
||||
}
|
||||
|
||||
public void ApplyModifiedProperties(Object[] targets)
|
||||
{
|
||||
if (!_propertiesChanged)
|
||||
return;
|
||||
|
||||
ApplyModifiedPropertiesInternal(targets);
|
||||
|
||||
_propertiesChanged = false;
|
||||
}
|
||||
|
||||
public virtual void OnSceneGUI(DC_SourceSettings target)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected abstract void OnContextSet();
|
||||
|
||||
protected abstract void DrawPropertiesInternal();
|
||||
|
||||
protected abstract void ApplyModifiedPropertiesInternal(Object[] targets);
|
||||
}
|
||||
|
||||
private class RendererSourceSettingsStrategyEditor : SourceSettingsStrategyEditor
|
||||
{
|
||||
private SerializedProperty _cullingMethodProp;
|
||||
private SerializedProperty _convexColliderProp;
|
||||
|
||||
protected override void OnContextSet()
|
||||
{
|
||||
SerializedProperty strategyProp = Context.FindProperty("_strategy");
|
||||
|
||||
_cullingMethodProp = strategyProp.FindPropertyRelative("_cullingMethod");
|
||||
_convexColliderProp = strategyProp.FindPropertyRelative("_convexCollider");
|
||||
}
|
||||
|
||||
protected override void DrawPropertiesInternal()
|
||||
{
|
||||
EditorGUILayout.PropertyField(_cullingMethodProp);
|
||||
EditorGUILayout.PropertyField(_convexColliderProp);
|
||||
}
|
||||
|
||||
protected override void ApplyModifiedPropertiesInternal(Object[] targets)
|
||||
{
|
||||
if (!_cullingMethodProp.hasMultipleDifferentValues)
|
||||
{
|
||||
foreach (var target in targets)
|
||||
{
|
||||
(target as DC_SourceSettings).GetStrategy<DC_RendererSourceSettingsStrategy>()
|
||||
.CullingMethod = (CullingMethod)_cullingMethodProp.enumValueIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_convexColliderProp.hasMultipleDifferentValues)
|
||||
{
|
||||
foreach (var target in targets)
|
||||
{
|
||||
(target as DC_SourceSettings).GetStrategy<DC_RendererSourceSettingsStrategy>()
|
||||
.ConvexCollider = _convexColliderProp.boolValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class LODGroupSourceSettingsStrategyEditor : SourceSettingsStrategyEditor
|
||||
{
|
||||
private SerializedProperty _cullingMethodProp;
|
||||
|
||||
protected override void OnContextSet()
|
||||
{
|
||||
_cullingMethodProp = Context
|
||||
.FindProperty("_strategy")
|
||||
.FindPropertyRelative("_cullingMethod");
|
||||
}
|
||||
|
||||
protected override void DrawPropertiesInternal()
|
||||
{
|
||||
EditorGUILayout.PropertyField(_cullingMethodProp);
|
||||
}
|
||||
|
||||
protected override void ApplyModifiedPropertiesInternal(Object[] targets)
|
||||
{
|
||||
if (!_cullingMethodProp.hasMultipleDifferentValues)
|
||||
{
|
||||
foreach (var target in targets)
|
||||
{
|
||||
(target as DC_SourceSettings).GetStrategy<DC_LODGroupSourceSettingsStrategy>()
|
||||
.CullingMethod = (CullingMethod)_cullingMethodProp.enumValueIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CustomSourceSettingsStrategyEditor : SourceSettingsStrategyEditor
|
||||
{
|
||||
private static BoxBoundsHandle BoundsHandle;
|
||||
|
||||
private SerializedProperty _strategyProp;
|
||||
private SerializedProperty _localBoundsProp;
|
||||
private SerializedProperty _onVisibleEventProp;
|
||||
private SerializedProperty _onInvisibleEventProp;
|
||||
|
||||
|
||||
public override void OnSceneGUI(DC_SourceSettings target)
|
||||
{
|
||||
if (BoundsHandle == null)
|
||||
BoundsHandle = new BoxBoundsHandle();
|
||||
|
||||
DC_CustomSourceSettingsStrategy strategy =
|
||||
target.GetStrategy<DC_CustomSourceSettingsStrategy>();
|
||||
|
||||
Bounds localBounds = strategy.LocalBounds;
|
||||
|
||||
BoundsHandle.center = target.transform.position + localBounds.center;
|
||||
BoundsHandle.size = localBounds.size;
|
||||
|
||||
BoundsHandle.DrawHandle();
|
||||
|
||||
localBounds.center = BoundsHandle.center - target.transform.position;
|
||||
localBounds.size = BoundsHandle.size;
|
||||
|
||||
strategy.LocalBounds = localBounds;
|
||||
}
|
||||
|
||||
|
||||
protected override void OnContextSet()
|
||||
{
|
||||
_strategyProp = Context.FindProperty("_strategy");
|
||||
_localBoundsProp = _strategyProp.FindPropertyRelative("_localBounds");
|
||||
_onVisibleEventProp = _strategyProp.FindPropertyRelative("_onVisible");
|
||||
_onInvisibleEventProp = _strategyProp.FindPropertyRelative("_onInvisible");
|
||||
}
|
||||
|
||||
protected override void DrawPropertiesInternal()
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (_strategyProp.hasMultipleDifferentValues)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Multiediting is not supported for such SourceType", MessageType.Info, true);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(_localBoundsProp);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(_onVisibleEventProp);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(_onInvisibleEventProp);
|
||||
}
|
||||
|
||||
protected override void ApplyModifiedPropertiesInternal(Object[] targets)
|
||||
{
|
||||
if (_strategyProp.hasMultipleDifferentValues)
|
||||
return;
|
||||
|
||||
Context.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem.Static
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(CameraZone))]
|
||||
public class CameraZoneEditor : Editor
|
||||
{
|
||||
protected new CameraZone target
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.target as CameraZone;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool DrawGizmo = true;
|
||||
private static BinaryTreeDrawer TreeDrawer;
|
||||
|
||||
private BoxBoundsHandle _boundsHandle;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_boundsHandle = new BoxBoundsHandle();
|
||||
|
||||
if (TreeDrawer == null)
|
||||
{
|
||||
TreeDrawer = new BinaryTreeDrawer();
|
||||
TreeDrawer.Color = Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (target.VisibilityTree != null)
|
||||
{
|
||||
DrawGizmo = EditorGUILayout.Toggle("Draw Gizmo", DrawGizmo);
|
||||
|
||||
EditorGUILayout.HelpBox("Cells Count : " + target.CellsCount, MessageType.None);
|
||||
|
||||
if (GUILayout.Button("Clear"))
|
||||
target.ClearVisibilityTree();
|
||||
}
|
||||
}
|
||||
|
||||
[DrawGizmo(GizmoType.Selected | GizmoType.Active)]
|
||||
private static void OnDrawGizmos(CameraZone cameraZone, GizmoType gizmoType)
|
||||
{
|
||||
if (!DrawGizmo)
|
||||
return;
|
||||
|
||||
if (cameraZone.VisibilityTree != null)
|
||||
{
|
||||
TreeDrawer.DrawTreeGizmos(cameraZone.VisibilityTree.Root);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSceneGUI()
|
||||
{
|
||||
if (target.VisibilityTree != null)
|
||||
return;
|
||||
|
||||
Transform transform = target.transform;
|
||||
|
||||
_boundsHandle.center = transform.position;
|
||||
_boundsHandle.size = transform.localScale;
|
||||
|
||||
_boundsHandle.DrawHandle();
|
||||
|
||||
transform.position = _boundsHandle.center;
|
||||
transform.localScale = _boundsHandle.size;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem.Static
|
||||
{
|
||||
[CustomEditor(typeof(StaticCullingCamera))]
|
||||
public class StaticCullingCameraEditor : Editor
|
||||
{
|
||||
private static bool ShowFrustum;
|
||||
|
||||
protected new StaticCullingCamera target
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.target as StaticCullingCamera;
|
||||
}
|
||||
}
|
||||
|
||||
private SerializedProperty _drawCellsProp;
|
||||
private SerializedProperty _toleranceProp;
|
||||
private Camera _camera;
|
||||
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_drawCellsProp = serializedObject.FindProperty("_drawCells");
|
||||
_toleranceProp = serializedObject.FindProperty("_tolerance");
|
||||
_camera = target.GetComponent<Camera>();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
ShowFrustum = EditorGUILayout.Toggle("Show Frustum", ShowFrustum);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
ResetSceneCamerasCullingMatrices();
|
||||
|
||||
EditorGUILayout.PropertyField(_drawCellsProp);
|
||||
_toleranceProp.floatValue = EditorGUILayout.Slider("Tolerance", _toleranceProp.floatValue, 0, 3);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void OnSceneGUI()
|
||||
{
|
||||
if (!Application.isPlaying)
|
||||
return;
|
||||
|
||||
if (!ShowFrustum)
|
||||
return;
|
||||
|
||||
foreach (var camera in SceneView.GetAllSceneCameras())
|
||||
camera.cullingMatrix = _camera.cullingMatrix;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
ResetSceneCamerasCullingMatrices();
|
||||
}
|
||||
|
||||
|
||||
private void ResetSceneCamerasCullingMatrices()
|
||||
{
|
||||
foreach (var camera in SceneView.GetAllSceneCameras())
|
||||
camera.ResetCullingMatrix();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem.Static
|
||||
{
|
||||
public class CameraZonesSelectionWindow : EditorWindow
|
||||
{
|
||||
private StaticCullingController _controller;
|
||||
|
||||
private static GUIStyle TitleLabelStyle;
|
||||
private static GUIStyle HeaderLabelStyle;
|
||||
private static GUIStyle ButtonGUIStyle;
|
||||
|
||||
|
||||
public void Initialize(StaticCullingController controller)
|
||||
{
|
||||
_controller = controller;
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (_controller == null)
|
||||
Close();
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Debug.Log("Can't open window in runtime");
|
||||
Close();
|
||||
}
|
||||
|
||||
if (TitleLabelStyle == null)
|
||||
CreateGUIStyles();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Camera Zones", TitleLabelStyle);
|
||||
EditorHelper.DrawSeparatorLine(1, 2);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
IReadOnlyList<CameraZone> cameraZones = _controller.CameraZones;
|
||||
|
||||
if (cameraZones != null)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < cameraZones.Count)
|
||||
{
|
||||
CameraZone zone = cameraZones[i];
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
EditorGUILayout.ObjectField(cameraZones[i], typeof(CameraZone), false);
|
||||
|
||||
if (GUILayout.Button("Select"))
|
||||
Select(zone);
|
||||
|
||||
if (GUILayout.Button("Clear"))
|
||||
Clear(zone);
|
||||
|
||||
if (GUILayout.Button("Delete"))
|
||||
Delete(zone);
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Create New", ButtonGUIStyle))
|
||||
CreateNew();
|
||||
|
||||
if (GUILayout.Button("Add Selected", ButtonGUIStyle))
|
||||
AddSelected();
|
||||
}
|
||||
|
||||
|
||||
private void CreateGUIStyles()
|
||||
{
|
||||
TitleLabelStyle = new GUIStyle();
|
||||
TitleLabelStyle.fontSize = 24;
|
||||
TitleLabelStyle.fontStyle = FontStyle.Bold;
|
||||
TitleLabelStyle.alignment = TextAnchor.MiddleCenter;
|
||||
TitleLabelStyle.normal.textColor = Color.white;
|
||||
|
||||
HeaderLabelStyle = new GUIStyle();
|
||||
HeaderLabelStyle.fontSize = 17;
|
||||
HeaderLabelStyle.fontStyle = FontStyle.Bold;
|
||||
HeaderLabelStyle.alignment = TextAnchor.MiddleLeft;
|
||||
HeaderLabelStyle.normal.textColor = Color.white;
|
||||
|
||||
ButtonGUIStyle = new GUIStyle(GUI.skin.button);
|
||||
ButtonGUIStyle.fontSize = 12;
|
||||
ButtonGUIStyle.fixedHeight = 24;
|
||||
ButtonGUIStyle.margin = new RectOffset(5, 5, 5, 5);
|
||||
ButtonGUIStyle.border = new RectOffset(0, 0, 0, 0);
|
||||
ButtonGUIStyle.padding = new RectOffset(5, 5, 5, 5);
|
||||
}
|
||||
|
||||
private void Select(CameraZone zone)
|
||||
{
|
||||
Selection.activeObject = zone.gameObject;
|
||||
}
|
||||
|
||||
private void Clear(CameraZone zone)
|
||||
{
|
||||
_controller.RemoveCameraZone(zone);
|
||||
}
|
||||
|
||||
private void Delete(CameraZone zone)
|
||||
{
|
||||
_controller.RemoveCameraZone(zone);
|
||||
|
||||
DestroyImmediate(zone.gameObject);
|
||||
}
|
||||
|
||||
private void CreateNew()
|
||||
{
|
||||
GameObject go = new GameObject("Camera Zone");
|
||||
go.transform.localScale = Vector3.one * 10;
|
||||
|
||||
CameraZone zone = go.AddComponent<CameraZone>();
|
||||
|
||||
_controller.AddCameraZone(zone);
|
||||
}
|
||||
|
||||
private void AddSelected()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
foreach (var go in Selection.gameObjects)
|
||||
{
|
||||
CameraZone[] zones = go.GetComponentsInChildren<CameraZone>();
|
||||
|
||||
if (zones == null)
|
||||
continue;
|
||||
|
||||
foreach (var zone in zones)
|
||||
{
|
||||
if (_controller.AddCameraZone(zone))
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("Added " + count + " new camera zones");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,961 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem.Static
|
||||
{
|
||||
public class SourcesSelectionWindow : EditorWindow
|
||||
{
|
||||
private static GUIStyle TitleLabelStyle;
|
||||
private static GUIStyle HeaderLabelStyle;
|
||||
private static GUIStyle ButtonGUIStyle;
|
||||
|
||||
private StaticCullingController _controller;
|
||||
private string[] _tabNames;
|
||||
private ITab[] _tabs;
|
||||
private int _tabIndex = 0;
|
||||
|
||||
|
||||
public void Initialize(StaticCullingController controller)
|
||||
{
|
||||
_controller = controller;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
name = "Objects Selection";
|
||||
|
||||
_tabNames = new string[] { "Cameras", "Renderers", "LODGroups", "Lights", "Custom" };
|
||||
_tabs = new ITab[]
|
||||
{
|
||||
new CamerasTab(),
|
||||
new RenderersTab(),
|
||||
new LODGroupsTab(),
|
||||
new LightsTab(),
|
||||
new CustomTab()
|
||||
};
|
||||
|
||||
foreach (var tab in _tabs)
|
||||
tab.Refresh();
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (_controller == null)
|
||||
Close();
|
||||
|
||||
if (Application.isPlaying)
|
||||
{
|
||||
Close();
|
||||
Debug.Log("Objects selection not available in runtime");
|
||||
}
|
||||
|
||||
if (TitleLabelStyle == null)
|
||||
CreateGUIStyles();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Objects Selection", TitleLabelStyle);
|
||||
|
||||
EditorHelper.DrawSeparatorLine(1, 2);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
_tabIndex = GUILayout.Toolbar(_tabIndex, _tabNames, ButtonGUIStyle);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
bool sceneChanged = false;
|
||||
|
||||
_tabs[_tabIndex].OnInspectorGUI(ref sceneChanged);
|
||||
|
||||
if (sceneChanged)
|
||||
{
|
||||
foreach (var tab in _tabs)
|
||||
tab.Refresh();
|
||||
|
||||
EditorUtility.SetDirty(_controller);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void CreateGUIStyles()
|
||||
{
|
||||
TitleLabelStyle = new GUIStyle();
|
||||
TitleLabelStyle.fontSize = 24;
|
||||
TitleLabelStyle.fontStyle = FontStyle.Bold;
|
||||
TitleLabelStyle.alignment = TextAnchor.MiddleCenter;
|
||||
TitleLabelStyle.normal.textColor = Color.white;
|
||||
|
||||
HeaderLabelStyle = new GUIStyle();
|
||||
HeaderLabelStyle.fontSize = 17;
|
||||
HeaderLabelStyle.fontStyle = FontStyle.Bold;
|
||||
HeaderLabelStyle.alignment = TextAnchor.MiddleLeft;
|
||||
HeaderLabelStyle.normal.textColor = Color.white;
|
||||
|
||||
ButtonGUIStyle = new GUIStyle(GUI.skin.button);
|
||||
ButtonGUIStyle.fontSize = 12;
|
||||
ButtonGUIStyle.fixedHeight = 24;
|
||||
ButtonGUIStyle.margin = new RectOffset(5, 5, 5, 5);
|
||||
ButtonGUIStyle.border = new RectOffset(0, 0, 0, 0);
|
||||
ButtonGUIStyle.padding = new RectOffset(5, 5, 5, 5);
|
||||
}
|
||||
|
||||
private void DrawCustomTab()
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.HelpBox("To set a custom CullingSource you need to manually attach " +
|
||||
"the 'StaticCullingSource' script to the object, specify the 'SourceType' as Custom, " +
|
||||
"and then configure the 'StaticCullingSource' component.", MessageType.Info);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Custom Sources : 124", HeaderLabelStyle);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.Toggle("DrawGizmo", true);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
GUILayout.Button("Clear All", ButtonGUIStyle);
|
||||
GUILayout.Button("Clear Selected", ButtonGUIStyle);
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Button("Select", ButtonGUIStyle);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Not Valid Custom Sources : 124", HeaderLabelStyle);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
GUILayout.Button("Print", ButtonGUIStyle);
|
||||
GUILayout.Button("Select", ButtonGUIStyle);
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Button("Clear All", ButtonGUIStyle);
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
|
||||
private interface ITab
|
||||
{
|
||||
void Refresh();
|
||||
|
||||
void OnInspectorGUI(ref bool sceneChanged);
|
||||
}
|
||||
|
||||
private abstract class TabTemplate : ITab
|
||||
{
|
||||
protected abstract string SourceName { get; }
|
||||
protected abstract bool CanExistsNotValidSources { get; }
|
||||
protected abstract bool ShowOnlyStaticToggle { get; }
|
||||
protected abstract bool ShowSelectButton { get; }
|
||||
protected abstract bool ShowVerifyButton { get; }
|
||||
|
||||
protected bool AssignOnlyStatic { get; private set; }
|
||||
protected int SourcesCount { get; private set; }
|
||||
protected int NotValidSourcesCount { get; private set; }
|
||||
|
||||
|
||||
public virtual void Refresh()
|
||||
{
|
||||
SourcesCount = 0;
|
||||
NotValidSourcesCount = 0;
|
||||
|
||||
foreach (var go in FindObjectsOfType<GameObject>())
|
||||
{
|
||||
if (ContainsSource(go))
|
||||
{
|
||||
SourcesCount++;
|
||||
|
||||
if (CanExistsNotValidSources && GetValidationError(go) != "")
|
||||
NotValidSourcesCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnInspectorGUI(ref bool sceneChanged)
|
||||
{
|
||||
BeforeOnGUI();
|
||||
|
||||
EditorGUILayout.LabelField(SourceName + " : " + SourcesCount, HeaderLabelStyle);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (ShowVerifyButton)
|
||||
{
|
||||
if (GUILayout.Button("Verify Sources", ButtonGUIStyle))
|
||||
VerifySources(ref sceneChanged);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
BeforeDrawContent();
|
||||
|
||||
if (ShowOnlyStaticToggle)
|
||||
AssignOnlyStatic = EditorGUILayout.Toggle("Assign Only Static", AssignOnlyStatic);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
DrawSourcesButtons(ref sceneChanged);
|
||||
|
||||
if (CanExistsNotValidSources)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Not Valid " + SourceName + " : " + NotValidSourcesCount,
|
||||
HeaderLabelStyle);
|
||||
|
||||
DrawNotValidSourcesButtons(ref sceneChanged);
|
||||
}
|
||||
|
||||
AfterOnGUI();
|
||||
}
|
||||
|
||||
|
||||
protected virtual void BeforeOnGUI()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void BeforeDrawContent()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void DrawSourcesButtons(ref bool sceneChanged)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
if (GUILayout.Button("Assign Auto", ButtonGUIStyle))
|
||||
AssignAutoButtonClick(ref sceneChanged);
|
||||
|
||||
if (GUILayout.Button("Clear All", ButtonGUIStyle))
|
||||
ClearAllButtonClick(ref sceneChanged);
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
if (GUILayout.Button("Assign Selected", ButtonGUIStyle))
|
||||
AssignSelectedButtonClick(ref sceneChanged);
|
||||
|
||||
if (GUILayout.Button("Clear Selected", ButtonGUIStyle))
|
||||
ClearSelectedButtonClick(ref sceneChanged);
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (ShowSelectButton)
|
||||
{
|
||||
if (GUILayout.Button("Select", ButtonGUIStyle))
|
||||
SelectButtonClick(ref sceneChanged);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void DrawNotValidSourcesButtons(ref bool sceneChanged)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.BeginVertical();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (GUILayout.Button("Print", ButtonGUIStyle))
|
||||
NotValidPrintButtonClick(ref sceneChanged);
|
||||
|
||||
if (GUILayout.Button("Select", ButtonGUIStyle))
|
||||
NotValidSelectButtonClick(ref sceneChanged);
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (GUILayout.Button("Clear All", ButtonGUIStyle))
|
||||
NotValidClearButtonClick(ref sceneChanged);
|
||||
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
protected virtual void AfterOnGUI()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected abstract bool ContainsSource(GameObject go);
|
||||
|
||||
protected abstract bool CanAssignTo(GameObject go);
|
||||
|
||||
protected abstract void AssignSourceTo(GameObject go);
|
||||
|
||||
protected abstract void ClearSourceFrom(GameObject go);
|
||||
|
||||
protected abstract bool ValidateSource(GameObject go, out string error);
|
||||
|
||||
protected abstract string GetValidationError(GameObject go);
|
||||
|
||||
|
||||
protected void VerifySources(ref bool sceneChanged)
|
||||
{
|
||||
foreach (var go in FindObjectsOfType<GameObject>().Where(go => ContainsSource(go)))
|
||||
ValidateSource(go, out string error);
|
||||
|
||||
sceneChanged = true;
|
||||
}
|
||||
|
||||
protected void AssignAutoButtonClick(ref bool sceneChanged)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
foreach (var go in FindObjectsOfType<GameObject>())
|
||||
{
|
||||
if (ContainsSource(go))
|
||||
continue;
|
||||
|
||||
if (AssignOnlyStatic && !go.isStatic)
|
||||
continue;
|
||||
|
||||
if (go.GetComponent<StaticCullingSource>() != null)
|
||||
continue;
|
||||
|
||||
if (go.GetComponent<CullingTarget>() != null)
|
||||
continue;
|
||||
|
||||
if (CanAssignTo(go))
|
||||
{
|
||||
AssignSourceTo(go);
|
||||
|
||||
sceneChanged = true;
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("Assigned " + count + " new sources");
|
||||
}
|
||||
|
||||
protected void AssignSelectedButtonClick(ref bool sceneChanged)
|
||||
{
|
||||
GameObject[] gos = Selection.gameObjects
|
||||
.SelectMany(go => go.GetComponentsInChildren<Transform>()
|
||||
.Select(t => t.gameObject))
|
||||
.ToArray();
|
||||
|
||||
int count = 0;
|
||||
|
||||
foreach (var go in gos)
|
||||
{
|
||||
if (ContainsSource(go))
|
||||
continue;
|
||||
|
||||
if (AssignOnlyStatic && !go.isStatic)
|
||||
continue;
|
||||
|
||||
if (go.GetComponent<StaticCullingSource>() != null)
|
||||
continue;
|
||||
|
||||
if (go.GetComponent<CullingTarget>() != null)
|
||||
continue;
|
||||
|
||||
if (CanAssignTo(go))
|
||||
{
|
||||
AssignSourceTo(go);
|
||||
|
||||
sceneChanged = true;
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("Assigned " + count + " new sources");
|
||||
}
|
||||
|
||||
protected void ClearAllButtonClick(ref bool sceneChanged)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
foreach (var go in FindObjectsOfType<GameObject>())
|
||||
{
|
||||
if (ContainsSource(go))
|
||||
{
|
||||
ClearSourceFrom(go);
|
||||
|
||||
sceneChanged = true;
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("Cleared " + count + " sources");
|
||||
}
|
||||
|
||||
protected void ClearSelectedButtonClick(ref bool sceneChanged)
|
||||
{
|
||||
GameObject[] gos = Selection.gameObjects
|
||||
.SelectMany(go => go.GetComponentsInChildren<Transform>()
|
||||
.Select(t => t.gameObject))
|
||||
.ToArray();
|
||||
|
||||
int count = 0;
|
||||
|
||||
foreach (var go in gos)
|
||||
{
|
||||
if (ContainsSource(go))
|
||||
{
|
||||
ClearSourceFrom(go);
|
||||
|
||||
sceneChanged = true;
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("Cleared " + count + " sources");
|
||||
}
|
||||
|
||||
protected void SelectButtonClick(ref bool sceneChanged)
|
||||
{
|
||||
GameObject[] gos = FindObjectsOfType<GameObject>()
|
||||
.Where(go => ContainsSource(go))
|
||||
.ToArray();
|
||||
|
||||
Selection.objects = gos;
|
||||
}
|
||||
|
||||
protected void NotValidPrintButtonClick(ref bool sceneChanged)
|
||||
{
|
||||
foreach (var go in FindObjectsOfType<GameObject>())
|
||||
{
|
||||
if (ContainsSource(go))
|
||||
{
|
||||
string error = GetValidationError(go);
|
||||
|
||||
if (error == "")
|
||||
continue;
|
||||
|
||||
Debug.Log(go.name + " : " + error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void NotValidClearButtonClick(ref bool sceneChanged)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
foreach (var go in FindObjectsOfType<GameObject>())
|
||||
{
|
||||
if (ContainsSource(go))
|
||||
{
|
||||
if (!ValidateSource(go, out string error))
|
||||
{
|
||||
ClearSourceFrom(go);
|
||||
|
||||
sceneChanged = true;
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log("Cleared " + count + " not valid sources");
|
||||
}
|
||||
|
||||
protected void NotValidSelectButtonClick(ref bool sceneChanged)
|
||||
{
|
||||
List<UnityEngine.Object> notValidGos = new List<UnityEngine.Object>();
|
||||
|
||||
foreach (var go in FindObjectsOfType<GameObject>())
|
||||
{
|
||||
if (ContainsSource(go))
|
||||
{
|
||||
string error = GetValidationError(go);
|
||||
|
||||
if (error != "")
|
||||
notValidGos.Add(go);
|
||||
}
|
||||
}
|
||||
|
||||
Selection.objects = notValidGos.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
private class CamerasTab : TabTemplate
|
||||
{
|
||||
protected override string SourceName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Cameras";
|
||||
}
|
||||
}
|
||||
protected override bool ShowOnlyStaticToggle
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
protected override bool CanExistsNotValidSources
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
protected override bool ShowVerifyButton
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
protected override bool ShowSelectButton
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void BeforeDrawContent()
|
||||
{
|
||||
StaticCullingCamera.DrawGizmo = EditorGUILayout.Toggle("Draw Gizmo",
|
||||
StaticCullingCamera.DrawGizmo);
|
||||
}
|
||||
|
||||
protected override bool ContainsSource(GameObject go)
|
||||
{
|
||||
return go.GetComponent<StaticCullingCamera>() != null;
|
||||
}
|
||||
|
||||
protected override bool CanAssignTo(GameObject go)
|
||||
{
|
||||
return go.activeInHierarchy && go.GetComponent<Camera>() != null;
|
||||
}
|
||||
|
||||
protected override void AssignSourceTo(GameObject go)
|
||||
{
|
||||
go.AddComponent<StaticCullingCamera>();
|
||||
}
|
||||
|
||||
protected override void ClearSourceFrom(GameObject go)
|
||||
{
|
||||
DestroyImmediate(go.GetComponent<StaticCullingCamera>());
|
||||
}
|
||||
|
||||
|
||||
protected override string GetValidationError(GameObject go)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
protected override bool ValidateSource(GameObject go, out string error)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
private class RenderersTab : TabTemplate
|
||||
{
|
||||
protected override string SourceName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Renderers";
|
||||
}
|
||||
}
|
||||
protected override bool ShowOnlyStaticToggle
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override bool CanExistsNotValidSources
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override bool ShowVerifyButton
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override bool ShowSelectButton
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override void BeforeDrawContent()
|
||||
{
|
||||
StaticCullingSource.DrawGizmoRenderers = EditorGUILayout.Toggle("Draw Gizmo",
|
||||
StaticCullingSource.DrawGizmoRenderers);
|
||||
}
|
||||
|
||||
protected override void AssignSourceTo(GameObject go)
|
||||
{
|
||||
StaticCullingSource source = go.AddComponent<StaticCullingSource>();
|
||||
source.SourceType = SourceType.MeshRenderer;
|
||||
}
|
||||
|
||||
protected override bool CanAssignTo(GameObject go)
|
||||
{
|
||||
MeshRenderer renderer = go.GetComponent<MeshRenderer>();
|
||||
|
||||
return go.activeInHierarchy && renderer != null && renderer.enabled &&
|
||||
go.GetComponentInParent<LODGroup>() == null;
|
||||
}
|
||||
|
||||
protected override void ClearSourceFrom(GameObject go)
|
||||
{
|
||||
DestroyImmediate(go.GetComponent<StaticCullingSource>());
|
||||
}
|
||||
|
||||
protected override string GetValidationError(GameObject go)
|
||||
{
|
||||
return go.GetComponent<StaticCullingSource>().ValidationError;
|
||||
}
|
||||
|
||||
protected override bool ContainsSource(GameObject go)
|
||||
{
|
||||
StaticCullingSource source = go.GetComponent<StaticCullingSource>();
|
||||
|
||||
return source != null && source.SourceType == SourceType.MeshRenderer;
|
||||
}
|
||||
|
||||
protected override bool ValidateSource(GameObject go, out string error)
|
||||
{
|
||||
StaticCullingSource source = go.GetComponent<StaticCullingSource>();
|
||||
|
||||
bool isValid = source.Validate();
|
||||
|
||||
error = source.ValidationError;
|
||||
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
|
||||
private class LODGroupsTab : TabTemplate
|
||||
{
|
||||
protected override string SourceName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "LODGroups";
|
||||
}
|
||||
}
|
||||
protected override bool CanExistsNotValidSources
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override bool ShowOnlyStaticToggle
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override bool ShowSelectButton
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
protected override bool ShowVerifyButton
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override void BeforeDrawContent()
|
||||
{
|
||||
StaticCullingSource.DrawGizmoLODGroups = EditorGUILayout.Toggle("Draw Gizmo",
|
||||
StaticCullingSource.DrawGizmoLODGroups);
|
||||
}
|
||||
|
||||
protected override bool ValidateSource(GameObject go, out string error)
|
||||
{
|
||||
StaticCullingSource source = go.GetComponent<StaticCullingSource>();
|
||||
|
||||
bool isValid = source.Validate();
|
||||
|
||||
error = source.ValidationError;
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
protected override string GetValidationError(GameObject go)
|
||||
{
|
||||
return go.GetComponent<StaticCullingSource>().ValidationError;
|
||||
}
|
||||
|
||||
protected override bool ContainsSource(GameObject go)
|
||||
{
|
||||
StaticCullingSource source = go.GetComponent<StaticCullingSource>();
|
||||
|
||||
return source != null && source.SourceType == SourceType.LODGroup;
|
||||
}
|
||||
|
||||
protected override bool CanAssignTo(GameObject go)
|
||||
{
|
||||
return go.activeInHierarchy && go.GetComponent<LODGroup>() != null;
|
||||
}
|
||||
|
||||
protected override void AssignSourceTo(GameObject go)
|
||||
{
|
||||
StaticCullingSource source = go.AddComponent<StaticCullingSource>();
|
||||
source.SourceType = SourceType.LODGroup;
|
||||
}
|
||||
|
||||
protected override void ClearSourceFrom(GameObject go)
|
||||
{
|
||||
DestroyImmediate(go.GetComponent<StaticCullingSource>());
|
||||
}
|
||||
}
|
||||
|
||||
private class LightsTab : TabTemplate
|
||||
{
|
||||
protected override string SourceName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Lights";
|
||||
}
|
||||
}
|
||||
protected override bool CanExistsNotValidSources
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override bool ShowOnlyStaticToggle
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
protected override bool ShowSelectButton
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override bool ShowVerifyButton
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override void BeforeOnGUI()
|
||||
{
|
||||
EditorGUILayout.HelpBox("To avoid errors, you can only add PointLights in this window. " +
|
||||
"To add other light sources - you need to manually " +
|
||||
"attach 'StaticCullingSource' script " +
|
||||
"to your Light, then specify SourceType as 'Light' " +
|
||||
"and set up the bounding box.", MessageType.Info);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
protected override void BeforeDrawContent()
|
||||
{
|
||||
StaticCullingSource.DrawGizmoLights = EditorGUILayout.Toggle("Draw Gizmo",
|
||||
StaticCullingSource.DrawGizmoLights);
|
||||
}
|
||||
|
||||
protected override bool ValidateSource(GameObject go, out string error)
|
||||
{
|
||||
StaticCullingSource source = go.GetComponent<StaticCullingSource>();
|
||||
|
||||
bool isValid = source.Validate();
|
||||
|
||||
error = source.ValidationError;
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
protected override string GetValidationError(GameObject go)
|
||||
{
|
||||
return go.GetComponent<StaticCullingSource>().ValidationError;
|
||||
}
|
||||
|
||||
protected override bool ContainsSource(GameObject go)
|
||||
{
|
||||
StaticCullingSource source = go.GetComponent<StaticCullingSource>();
|
||||
|
||||
return source != null && source.SourceType == SourceType.Light;
|
||||
}
|
||||
|
||||
protected override bool CanAssignTo(GameObject go)
|
||||
{
|
||||
Light light = go.GetComponent<Light>();
|
||||
|
||||
return light != null && light.type == LightType.Point;
|
||||
}
|
||||
|
||||
protected override void AssignSourceTo(GameObject go)
|
||||
{
|
||||
StaticCullingSource source = go.AddComponent<StaticCullingSource>();
|
||||
source.SourceType = SourceType.Light;
|
||||
}
|
||||
|
||||
protected override void ClearSourceFrom(GameObject go)
|
||||
{
|
||||
DestroyImmediate(go.GetComponent<StaticCullingSource>());
|
||||
}
|
||||
}
|
||||
|
||||
private class CustomTab : TabTemplate
|
||||
{
|
||||
protected override string SourceName
|
||||
{
|
||||
get
|
||||
{
|
||||
return "Custom";
|
||||
}
|
||||
}
|
||||
protected override bool CanExistsNotValidSources
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override bool ShowOnlyStaticToggle
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
protected override bool ShowSelectButton
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override bool ShowVerifyButton
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override void BeforeOnGUI()
|
||||
{
|
||||
EditorGUILayout.HelpBox("To set a custom CullingSource you need to manually attach " +
|
||||
"the 'StaticCullingSource' script to the object, specify the 'SourceType' as Custom, " +
|
||||
"and then configure the 'StaticCullingSource' component.", MessageType.Info);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
protected override void BeforeDrawContent()
|
||||
{
|
||||
StaticCullingSource.DrawGizmoCustom = EditorGUILayout.Toggle("Draw Gizmo",
|
||||
StaticCullingSource.DrawGizmoCustom);
|
||||
}
|
||||
|
||||
protected override void DrawSourcesButtons(ref bool sceneChanged)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
if (GUILayout.Button("Clear All", ButtonGUIStyle))
|
||||
ClearAllButtonClick(ref sceneChanged);
|
||||
|
||||
if (GUILayout.Button("Clear Selected", ButtonGUIStyle))
|
||||
ClearSelectedButtonClick(ref sceneChanged);
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (ShowSelectButton)
|
||||
{
|
||||
if (GUILayout.Button("Select", ButtonGUIStyle))
|
||||
SelectButtonClick(ref sceneChanged);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool ContainsSource(GameObject go)
|
||||
{
|
||||
StaticCullingSource source = go.GetComponent<StaticCullingSource>();
|
||||
|
||||
return source != null && source.SourceType == SourceType.Custom;
|
||||
}
|
||||
|
||||
protected override bool CanAssignTo(GameObject go)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
protected override void AssignSourceTo(GameObject go)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
protected override void ClearSourceFrom(GameObject go)
|
||||
{
|
||||
DestroyImmediate(go.GetComponent<StaticCullingSource>());
|
||||
}
|
||||
|
||||
protected override string GetValidationError(GameObject go)
|
||||
{
|
||||
return go.GetComponent<StaticCullingSource>().ValidationError;
|
||||
}
|
||||
|
||||
protected override bool ValidateSource(GameObject go, out string error)
|
||||
{
|
||||
StaticCullingSource source = go.GetComponent<StaticCullingSource>();
|
||||
|
||||
bool isValid = source.Validate();
|
||||
|
||||
error = source.ValidationError;
|
||||
|
||||
return isValid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,236 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.EditorTools;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem.Static
|
||||
{
|
||||
[CustomEditor(typeof(StaticCullingController))]
|
||||
public class StaticCullingControllerEditor : Editor
|
||||
{
|
||||
protected new StaticCullingController target
|
||||
{
|
||||
get
|
||||
{
|
||||
return (StaticCullingController)base.target;
|
||||
}
|
||||
}
|
||||
|
||||
private static GUIStyle TitleLabelStyle;
|
||||
private static GUIStyle HeaderLabelStyle;
|
||||
private static GUIStyle ButtonGUIStyle;
|
||||
|
||||
private bool _sceneContainsBakedData;
|
||||
|
||||
|
||||
[MenuItem("Tools/NGSTools/Advanced Culling System/Static")]
|
||||
private static void CreateController()
|
||||
{
|
||||
GameObject go = new GameObject("StaticCullingController");
|
||||
|
||||
go.AddComponent<StaticCullingController>();
|
||||
|
||||
Selection.activeGameObject = go;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
CreateLayerIfNotExist();
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (TitleLabelStyle == null)
|
||||
CreateGUIStyles();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Static Culling", TitleLabelStyle);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Step 1. Objects Selection", HeaderLabelStyle);
|
||||
EditorHelper.DrawSeparatorLine(1, 2);
|
||||
|
||||
DrawStep1();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Step 2. Scene Partitioning", HeaderLabelStyle);
|
||||
EditorHelper.DrawSeparatorLine(1, 2);
|
||||
|
||||
DrawStep2();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Step 3. Camera Zones", HeaderLabelStyle);
|
||||
EditorHelper.DrawSeparatorLine(1, 2);
|
||||
|
||||
DrawStep3();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.LabelField("Step 4. Baking", HeaderLabelStyle);
|
||||
EditorHelper.DrawSeparatorLine(1, 2);
|
||||
|
||||
DrawStep4();
|
||||
}
|
||||
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
_sceneContainsBakedData = false;
|
||||
|
||||
if (FindObjectsOfType<CullingTarget>().Length > 0)
|
||||
{
|
||||
_sceneContainsBakedData = true;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var zone in FindObjectsOfType<CameraZone>())
|
||||
{
|
||||
if (zone.VisibilityTree != null && zone.VisibilityTree.CullingTargets != null)
|
||||
{
|
||||
_sceneContainsBakedData = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateLayerIfNotExist()
|
||||
{
|
||||
string layer = StaticCullingPreferences.LayerName;
|
||||
|
||||
if (!LayersHelper.IsLayerExist(layer))
|
||||
{
|
||||
LayersHelper.CreateLayer(layer);
|
||||
LayersHelper.DisableCollisions(LayerMask.NameToLayer(layer));
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateGUIStyles()
|
||||
{
|
||||
TitleLabelStyle = new GUIStyle();
|
||||
TitleLabelStyle.fontSize = 24;
|
||||
TitleLabelStyle.fontStyle = FontStyle.Bold;
|
||||
TitleLabelStyle.alignment = TextAnchor.MiddleCenter;
|
||||
TitleLabelStyle.normal.textColor = Color.white;
|
||||
|
||||
HeaderLabelStyle = new GUIStyle();
|
||||
HeaderLabelStyle.fontSize = 17;
|
||||
HeaderLabelStyle.fontStyle = FontStyle.Bold;
|
||||
HeaderLabelStyle.alignment = TextAnchor.MiddleLeft;
|
||||
HeaderLabelStyle.normal.textColor = Color.white;
|
||||
|
||||
ButtonGUIStyle = new GUIStyle(GUI.skin.button);
|
||||
ButtonGUIStyle.fontSize = 12;
|
||||
ButtonGUIStyle.fixedHeight = 24;
|
||||
ButtonGUIStyle.margin = new RectOffset(5, 5, 5, 5);
|
||||
ButtonGUIStyle.border = new RectOffset(0, 0, 0, 0);
|
||||
ButtonGUIStyle.padding = new RectOffset(5, 5, 5, 5);
|
||||
}
|
||||
|
||||
private void DrawStep1()
|
||||
{
|
||||
EditorGUILayout.HelpBox("Add cameras and objects to be culled", MessageType.None);
|
||||
|
||||
if (GUILayout.Button("Open Selection Tool", ButtonGUIStyle))
|
||||
{
|
||||
EditorWindow.GetWindow<SourcesSelectionWindow>().Initialize(target);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawStep2()
|
||||
{
|
||||
EditorGUILayout.HelpBox("Partition the scene into cells of optimal size. " +
|
||||
"If a cell is visible, all objects inside this cell will be enabled. " +
|
||||
"The more cells - the more objects will be culled, " +
|
||||
"but the longer the baking time will be.", MessageType.None);
|
||||
|
||||
target.DrawGeometryTreeGizmo = EditorGUILayout.Toggle("Draw Gizmo",
|
||||
target.DrawGeometryTreeGizmo);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
target.GeometryTreeDepth = EditorGUILayout.IntSlider("Partition",
|
||||
target.GeometryTreeDepth, 7, 20);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
EditorUtility.SetDirty(target);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Update", ButtonGUIStyle))
|
||||
target.CreatePreviewGeometryTree();
|
||||
}
|
||||
|
||||
private void DrawStep3()
|
||||
{
|
||||
EditorGUILayout.HelpBox("Select the areas where cameras can be located during gameplay. " +
|
||||
"Divide these areas into cells. " +
|
||||
"The smaller the cell, the more accurate the objects will be culled, " +
|
||||
"but the longer the baking time.", MessageType.None);
|
||||
|
||||
target.DrawCameraZones = EditorGUILayout.Toggle("Draw Gizmo", target.DrawCameraZones);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
target.CellSize = EditorGUILayout.FloatField("Cell Size", target.CellSize);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
EditorUtility.SetDirty(target);
|
||||
|
||||
EditorGUILayout.HelpBox("Total Cells Count : " + target.TotalCellsCount, MessageType.None);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Update", ButtonGUIStyle))
|
||||
target.CreatePreviewCameraZones();
|
||||
|
||||
if (GUILayout.Button("Open Selection Tool", ButtonGUIStyle))
|
||||
{
|
||||
var window = EditorWindow.GetWindow<CameraZonesSelectionWindow>();
|
||||
window.Initialize(target);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawStep4()
|
||||
{
|
||||
EditorGUILayout.HelpBox("Check the settings in each step again. " +
|
||||
"Specify the number of rays per unit and press bake.", MessageType.None);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
target.RaysPerUnit = EditorGUILayout.FloatField("Rays Per Unit", target.RaysPerUnit);
|
||||
target.MaxRaysPerSource = EditorGUILayout.IntField("Max Rays Per Source", target.MaxRaysPerSource);
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Bake", ButtonGUIStyle))
|
||||
{
|
||||
target.Bake();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
EditorGUI.BeginDisabledGroup(!_sceneContainsBakedData);
|
||||
|
||||
if (GUILayout.Button("Clear", ButtonGUIStyle))
|
||||
{
|
||||
target.Clear();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
EditorUtility.SetDirty(target);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,198 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
|
||||
namespace NGS.AdvancedCullingSystem.Static
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(StaticCullingSource))]
|
||||
public class StaticCullingSourceEditor : Editor
|
||||
{
|
||||
protected new StaticCullingSource target
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.target as StaticCullingSource;
|
||||
}
|
||||
}
|
||||
|
||||
private SerializedProperty _validationErrorProp;
|
||||
private SerializedProperty _sourceTypeProp;
|
||||
private SerializedProperty _strategyProp;
|
||||
private BoxBoundsHandle _boundsHandle;
|
||||
|
||||
|
||||
public void OnEnable()
|
||||
{
|
||||
_boundsHandle = new BoxBoundsHandle();
|
||||
|
||||
_validationErrorProp = serializedObject.FindProperty("_validationError");
|
||||
_sourceTypeProp = serializedObject.FindProperty("_sourceType");
|
||||
_strategyProp = serializedObject.FindProperty("_strategy");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
DrawHelpBoxes();
|
||||
|
||||
if (DrawProperties())
|
||||
ApplyModifiedProperties();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
DrawStrategyProperties();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (GUILayout.Button("Verify"))
|
||||
{
|
||||
foreach (var target in targets)
|
||||
{
|
||||
StaticCullingSource current = target as StaticCullingSource;
|
||||
|
||||
if (current.Validate())
|
||||
Debug.Log(current.gameObject.name + " is valid");
|
||||
else
|
||||
Debug.Log(current.gameObject.name + " not valid");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSceneGUI()
|
||||
{
|
||||
SourceType type = target.SourceType;
|
||||
|
||||
Bounds localBounds = default;
|
||||
|
||||
if (type == SourceType.Light)
|
||||
localBounds = ((LightStaticCullingSourceStrategy)target.Strategy).LocalBounds;
|
||||
|
||||
else if (type == SourceType.Custom)
|
||||
localBounds = ((CustomStaticCullingSourceStrategy)target.Strategy).LocalBounds;
|
||||
|
||||
else
|
||||
return;
|
||||
|
||||
_boundsHandle.center = target.transform.position + localBounds.center;
|
||||
_boundsHandle.size = localBounds.size;
|
||||
|
||||
_boundsHandle.DrawHandle();
|
||||
|
||||
localBounds.center = _boundsHandle.center - target.transform.position;
|
||||
localBounds.size = _boundsHandle.size;
|
||||
|
||||
if (type == SourceType.Light)
|
||||
((LightStaticCullingSourceStrategy)target.Strategy).LocalBounds = localBounds;
|
||||
|
||||
else if (type == SourceType.Custom)
|
||||
((CustomStaticCullingSourceStrategy)target.Strategy).LocalBounds = localBounds;
|
||||
}
|
||||
|
||||
|
||||
private void DrawHelpBoxes()
|
||||
{
|
||||
if (!_validationErrorProp.hasMultipleDifferentValues)
|
||||
{
|
||||
string validationError = _validationErrorProp.stringValue;
|
||||
|
||||
if (validationError != "")
|
||||
EditorGUILayout.HelpBox(validationError, MessageType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private bool DrawProperties()
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
EditorGUILayout.PropertyField(_sourceTypeProp);
|
||||
|
||||
return EditorGUI.EndChangeCheck();
|
||||
}
|
||||
|
||||
private void ApplyModifiedProperties()
|
||||
{
|
||||
foreach (var target in targets)
|
||||
{
|
||||
StaticCullingSource current = target as StaticCullingSource;
|
||||
|
||||
if (!_sourceTypeProp.hasMultipleDifferentValues)
|
||||
current.SourceType = (SourceType) _sourceTypeProp.enumValueIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void DrawStrategyProperties()
|
||||
{
|
||||
if (_sourceTypeProp.hasMultipleDifferentValues)
|
||||
return;
|
||||
|
||||
SourceType type = (SourceType) _sourceTypeProp.enumValueIndex;
|
||||
|
||||
if (type == SourceType.MeshRenderer)
|
||||
DrawMeshRendererSourceStrategy();
|
||||
|
||||
else if (type == SourceType.LODGroup)
|
||||
DrawLODGroupSourceStrategy();
|
||||
|
||||
else if (type == SourceType.Light)
|
||||
DrawLightSourceStrategy();
|
||||
|
||||
else if (type == SourceType.Custom)
|
||||
DrawCustomSourceStrategy();
|
||||
else
|
||||
throw new System.NotSupportedException();
|
||||
}
|
||||
|
||||
private void DrawMeshRendererSourceStrategy()
|
||||
{
|
||||
SerializedProperty cullingMethodProp = _strategyProp.FindPropertyRelative("_cullingMethod");
|
||||
SerializedProperty isOccluderProp = _strategyProp.FindPropertyRelative("_isOccluder");
|
||||
|
||||
EditorGUILayout.PropertyField(cullingMethodProp);
|
||||
EditorGUILayout.PropertyField(isOccluderProp);
|
||||
}
|
||||
|
||||
private void DrawLODGroupSourceStrategy()
|
||||
{
|
||||
SerializedProperty isOccluderProp = _strategyProp.FindPropertyRelative("_isOccluder");
|
||||
SerializedProperty cullingMethodProp = _strategyProp.FindPropertyRelative("_cullingMethod");
|
||||
|
||||
EditorGUILayout.PropertyField(cullingMethodProp);
|
||||
EditorGUILayout.PropertyField(isOccluderProp);
|
||||
}
|
||||
|
||||
private void DrawLightSourceStrategy()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void DrawCustomSourceStrategy()
|
||||
{
|
||||
SerializedProperty isOccluderProp = _strategyProp.FindPropertyRelative("_isOccluder");
|
||||
SerializedProperty onVisibleProp = _strategyProp.FindPropertyRelative("_onVisible");
|
||||
SerializedProperty onInvisibleProp = _strategyProp.FindPropertyRelative("_onInvisible");
|
||||
|
||||
EditorGUILayout.PropertyField(isOccluderProp);
|
||||
|
||||
if (!isOccluderProp.hasMultipleDifferentValues && isOccluderProp.boolValue)
|
||||
{
|
||||
SerializedProperty collidersProp = _strategyProp.FindPropertyRelative("_colliders");
|
||||
|
||||
EditorGUILayout.PropertyField(collidersProp);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(onVisibleProp);
|
||||
EditorGUILayout.PropertyField(onInvisibleProp);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user