10using System.Collections.Generic;
17 #pragma warning disable 0649
19 private int _rendererLod = 2;
22 private int _subMeshLod = 3;
25 private Material _material;
28 private bool _overrideShadowDistance =
false;
29 #pragma warning restore 0649
31 private List<GameObject> _renderers =
new List<GameObject>();
32 private Mesh _subMesh =
null;
35 _rendererLod = Mathf.Clamp(_rendererLod, 1, 3);
36 _subMeshLod = Mathf.Clamp(_subMeshLod, 1, 3);
41 if (_overrideShadowDistance && Application.isPlaying) {
42 QualitySettings.shadowDistance = transform.lossyScale.x * 10;
45 if (_subMesh ==
null) {
46 for (
int i = 0; i < _renderers.Count; i++) {
47 DestroyImmediate(_renderers[i]);
51 _subMesh = generateMengerMesh(_subMeshLod);
53 int size = Mathf.RoundToInt(Mathf.Pow(3, _rendererLod));
54 for (
int x = 0; x < size; x++) {
55 for (
int y = 0; y < size; y++) {
56 for (
int z = 0; z < size; z++) {
57 if (isSpaceFilled(x, y, z, size / 3)) {
58 GameObject subRenderer =
new GameObject(
"MengerPiece");
59 subRenderer.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
60 subRenderer.transform.parent = transform;
61 subRenderer.transform.localPosition =
new Vector3(x, y, z) / size + Vector3.one * 0.5f / size - Vector3.one * 0.5f;
62 subRenderer.transform.localRotation = Quaternion.identity;
63 subRenderer.transform.localScale = Vector3.one / size;
65 subRenderer.AddComponent<MeshFilter>().mesh = _subMesh;
66 subRenderer.AddComponent<MeshRenderer>().sharedMaterial = _material;
67 _renderers.Add(subRenderer);
75 private Mesh generateMengerMesh(
int lod) {
76 Mesh mesh =
new Mesh();
77 mesh.name =
"MengerMesh";
79 int size = Mathf.RoundToInt(Mathf.Pow(3, _subMeshLod));
81 bool[,,] _isFilled =
new bool[size, size, size];
82 for (
int x = 0; x < size; x++) {
83 for (
int y = 0; y < size; y++) {
84 for (
int z = 0; z < size; z++) {
85 if (isSpaceFilled(x, y, z, size / 3)) {
86 _isFilled[x, y, z] =
true;
92 List<Vector3> verts =
new List<Vector3>();
93 List<int> tris =
new List<int>();
95 float quadRadius = 0.5f / size;
97 for (
int x = 0; x < size; x++) {
98 for (
int y = 0; y < size; y++) {
99 for (
int z = 0; z < size; z++) {
100 if (_isFilled[x, y, z]) {
101 Vector3 position =
new Vector3(x, y, z) / size + Vector3.one * quadRadius - Vector3.one * 0.5f;
103 if (x == 0 || !_isFilled[x - 1, y, z]) {
104 addQuad(verts, tris, position + Vector3.left * quadRadius, Vector3.forward, Vector3.up, quadRadius);
106 if (x == size - 1 || !_isFilled[x + 1, y, z]) {
107 addQuad(verts, tris, position + Vector3.right * quadRadius, Vector3.up, Vector3.forward, quadRadius);
110 if (y == 0 || !_isFilled[x, y - 1, z]) {
111 addQuad(verts, tris, position + Vector3.down * quadRadius, Vector3.right, Vector3.forward, quadRadius);
113 if (y == size - 1 || !_isFilled[x, y + 1, z]) {
114 addQuad(verts, tris, position + Vector3.up * quadRadius, Vector3.forward, Vector3.right, quadRadius);
117 if (z == 0 || !_isFilled[x, y, z - 1]) {
118 addQuad(verts, tris, position + Vector3.back * quadRadius, Vector3.up, Vector3.right, quadRadius);
120 if (z == size - 1 || !_isFilled[x, y, z + 1]) {
121 addQuad(verts, tris, position + Vector3.forward * quadRadius, Vector3.right, Vector3.up, quadRadius);
128 List<Vector2> uvs =
new List<Vector2>();
129 for (
int i = 0; i < verts.Count; i++) {
133 mesh.SetVertices(verts);
135 mesh.SetIndices(tris.ToArray(), MeshTopology.Triangles, 0);
136 mesh.RecalculateNormals();
137 mesh.RecalculateBounds();
139 mesh.UploadMeshData(
true);
144 private void addQuad(List<Vector3> verts, List<int> tris, Vector3 center, Vector3 axisA, Vector3 axisB,
float radius) {
145 tris.Add(verts.Count + 0);
146 tris.Add(verts.Count + 1);
147 tris.Add(verts.Count + 2);
149 tris.Add(verts.Count + 0);
150 tris.Add(verts.Count + 2);
151 tris.Add(verts.Count + 3);
153 verts.Add(center + axisA * radius + axisB * radius);
154 verts.Add(center - axisA * radius + axisB * radius);
155 verts.Add(center - axisA * radius - axisB * radius);
156 verts.Add(center + axisA * radius - axisB * radius);
159 private bool isSpaceFilled(
int x,
int y,
int z,
int size) {
161 return spaceFilledBaseCase(x, y, z);
164 if (!spaceFilledBaseCase(x / size, y / size, z / size)) {
168 x -= (x / size) * size;
169 y -= (y / size) * size;
170 z -= (z / size) * size;
172 return isSpaceFilled(x, y, z, size / 3);
175 private bool spaceFilledBaseCase(
int x,
int y,
int z) {