Tanoda
ColliderInterpolator.cs
Go to the documentation of this file.
1using System.Linq;
2using System.Threading.Tasks;
3using UnityEngine;
4
6{
7 public class ColliderInterpolator : MonoBehaviour
8 {
9 private const string ColliderObjectPrefix = "UCI_";
10 [SerializeField] private float _divisionUnitLength = 0.5f;
11
12 public async void Generate()
13 {
14 var colliderObjectName = $"{ColliderObjectPrefix}{gameObject.name}";
15 RemoveOldColliders(colliderObjectName);
16
17 var meshCollider = gameObject.AddComponent<MeshCollider>();
18 var bounds = meshCollider.bounds;
19
20 Vector3[] gridPositions;
21 int xDivisionCount, yDivisionCount, zDivisionCount;
22 BoundsDivider.Divide(bounds, _divisionUnitLength, out gridPositions, out xDivisionCount,
23 out yDivisionCount, out zDivisionCount);
24
25 var tmpColliders = new Collider[1];
26 var positionCount = gridPositions.Length;
27 var hasColliderPosition = new bool[xDivisionCount * yDivisionCount * zDivisionCount];
28 for (var i = 0; i < positionCount; i++)
29 {
30 var position = gridPositions[i];
31 if (Physics.OverlapSphereNonAlloc(position, _divisionUnitLength / 2f, tmpColliders) == 0) continue;
32
33 hasColliderPosition[i] = true;
34 }
35
36 var colliderObject = new GameObject(colliderObjectName);
37 colliderObject.transform.SetParent(transform);
38 var numberofcollidersnow = 0;
39 while (hasColliderPosition.Any(p => p))
40 {
41 await Task.Delay(1);
42 var combineIndex = 0;
43 var combineCountMax = int.MinValue;
44 var xCombineEdgeCount = 0;
45 var yCombineEdgeCount = 0;
46 var zCombineEdgeCount = 0;
47 for (var i = 0; i < positionCount; i++)
48 {
49 if (!hasColliderPosition[i]) continue;
50
51 var checkIndex = i;
52 var xEdgeCount = 0;
53 while (checkIndex >= 0 && checkIndex < positionCount && hasColliderPosition[checkIndex])
54 {
55 checkIndex += zDivisionCount * yDivisionCount;
56 xEdgeCount++;
57
58 if (checkIndex % (zDivisionCount * yDivisionCount) == 0) break;
59 }
60
61 checkIndex = i;
62 var yEdgeCount = 0;
63 while (checkIndex >= 0 && checkIndex < positionCount && hasColliderPosition[checkIndex])
64 {
65 checkIndex += zDivisionCount;
66 yEdgeCount++;
67
68 if (checkIndex % (zDivisionCount * yDivisionCount) / zDivisionCount == 0) break;
69 }
70
71 checkIndex = i;
72 var zEdgeCount = 0;
73 while (checkIndex >= 0 && checkIndex < positionCount && hasColliderPosition[checkIndex])
74 {
75 checkIndex++;
76 zEdgeCount++;
77
78 if (checkIndex % zDivisionCount == 0) break;
79 }
80
81 var c = 0;
82 var resultX = 0;
83 var resultY = 0;
84 var resultZ = 0;
85 for (var x = 1; x <= xEdgeCount; x++)
86 for (var y = 1; y <= yEdgeCount; y++)
87 for (var z = 1; z <= zEdgeCount; z++)
88 {
89 if (!IsValidCubes(hasColliderPosition, i, x, y, z, yDivisionCount, zDivisionCount)) continue;
90
91 var count = x * y * z;
92 if (count < c) continue;
93
94 c = count;
95 resultX = x;
96 resultY = y;
97 resultZ = z;
98 }
99
100 xEdgeCount = resultX;
101 yEdgeCount = resultY;
102 zEdgeCount = resultZ;
103
104 var margeCount = xEdgeCount * yEdgeCount * zEdgeCount;
105 if (margeCount <= combineCountMax) continue;
106
107 combineIndex = i;
108 xCombineEdgeCount = xEdgeCount;
109 yCombineEdgeCount = yEdgeCount;
110 zCombineEdgeCount = zEdgeCount;
111 combineCountMax = margeCount;
112 }
113
114 for (var x = 0; x < xCombineEdgeCount; x++)
115 for (var y = 0; y < yCombineEdgeCount; y++)
116 for (var z = 0; z < zCombineEdgeCount; z++)
117 {
118 var index = combineIndex + zDivisionCount * yDivisionCount * x + zDivisionCount * y + z;
119 hasColliderPosition[index] = false;
120 }
121
122 var collider = colliderObject.AddComponent<BoxCollider>();
123 collider.center = gridPositions[combineIndex] +
124 new Vector3(xCombineEdgeCount, yCombineEdgeCount, zCombineEdgeCount) *
125 _divisionUnitLength / 2f - Vector3.one * _divisionUnitLength / 2f;
126 collider.size = new Vector3(xCombineEdgeCount, yCombineEdgeCount, zCombineEdgeCount) *
127 _divisionUnitLength;
128 numberofcollidersnow++;
129 if (numberofcollidersnow >= 31)
130 {
131 colliderObject = new GameObject(colliderObjectName + $"_{numberofcollidersnow}");
132 colliderObject.transform.SetParent(transform);
133 numberofcollidersnow = 0;
134 }
135 }
136
137 DestroyImmediate(meshCollider);
138 }
139
140 void RemoveOldColliders(string colliderObjectName)
141 {
142 var child = transform.Find(colliderObjectName);
143 if (child != null) DestroyImmediate(child.gameObject);
144 }
145
146 bool IsValidCubes(bool[] hasCollider, int index, int xEdgeCount, int yEdgeCount, int zEdgeCount,
147 int yDivisionCount, int zDivisionCount)
148 {
149 for (var x = 0; x < xEdgeCount; x++)
150 for (var y = 0; y < yEdgeCount; y++)
151 for (var z = 0; z < zEdgeCount; z++)
152 {
153 var i = index + x * yDivisionCount * zDivisionCount + y * zDivisionCount + z;
154 if (hasCollider[i]) continue;
155
156 return false;
157 }
158
159 return true;
160 }
161 }
162}