Files
Zombie/Assets/MantisLODEditor/Runtime/ProgressiveMeshRuntime.cs

696 lines
24 KiB
C#

/*--------------------------------------------------------
ProgressiveMeshRuntime.cs
Created by MINGFEN WANG on 13-12-26.
Copyright (c) 2013 MINGFEN WANG. All rights reserved.
http://www.mesh-online.net/
--------------------------------------------------------*/
using UnityEngine;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
using System;
using System.Collections.Generic;
namespace MantisLODEditor
{
public class Lod_Mesh
{
public Mesh mesh;
public int triangle_count;
}
public class ProgressiveMeshRuntime : MonoBehaviour
{
// Drag a reference or assign it with code
public ProgressiveMesh progressiveMesh = null;
// Optional fields
public Text fpsHint = null;
public Text lodHint = null;
public Text triangleHint = null;
// Clamp lod to [minLod, maxLod]
[HideInInspector]
public int[] mesh_lod_range = null;
[HideInInspector]
public bool never_cull = true;
[HideInInspector]
public int lod_strategy = 1;
[HideInInspector]
public float cull_ratio = 0.1f;
[HideInInspector]
public float disappear_distance = 250.0f;
[HideInInspector]
public float updateInterval = 0.25f;
private Component[] allFilters = null;
private Component[] allRenderers = null;
private Mesh[] shared_meshes = null;
private string[] mesh_uuids = null;
private int current_lod = -1;
private Component[] allBasicRenderers = null;
// How often to check lod changes, default four times per second.
// You may increase the value to balance the load if you have hundreds of 3d models in the scene.
private float currentTimeToInterval = 0.0f;
private bool culled = false;
private bool working = false;
#if UNITY_EDITOR
[MenuItem("Window/Mantis LOD Editor/Component/Runtime/Progressive Mesh Runtime")]
public static void AddComponent()
{
GameObject SelectedObject = Selection.activeGameObject;
if (SelectedObject)
{
// Register root object for undo.
Undo.RegisterCreatedObjectUndo(SelectedObject.AddComponent(typeof(ProgressiveMeshRuntime)), "Add Progressive Mesh Runtime");
}
}
[MenuItem("Window/Mantis LOD Editor/Component/Runtime/Progressive Mesh Runtime", true)]
static bool ValidateAddComponent()
{
// Return false if no gameobject is selected.
return Selection.activeGameObject != null;
}
#endif
void Awake()
{
get_all_meshes();
}
// Use this for initialization
void Start()
{
}
private float ratio_of_screen()
{
Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
foreach (Component child in allBasicRenderers)
{
Renderer rend = (Renderer)child;
Vector3 center = rend.bounds.center;
float radius = rend.bounds.extents.magnitude;
Vector3[] six_points = new Vector3[6];
six_points[0] = Camera.main.WorldToScreenPoint(new Vector3(center.x - radius, center.y, center.z));
six_points[1] = Camera.main.WorldToScreenPoint(new Vector3(center.x + radius, center.y, center.z));
six_points[2] = Camera.main.WorldToScreenPoint(new Vector3(center.x, center.y - radius, center.z));
six_points[3] = Camera.main.WorldToScreenPoint(new Vector3(center.x, center.y + radius, center.z));
six_points[4] = Camera.main.WorldToScreenPoint(new Vector3(center.x, center.y, center.z - radius));
six_points[5] = Camera.main.WorldToScreenPoint(new Vector3(center.x, center.y, center.z + radius));
foreach (Vector3 v in six_points)
{
if (v.x < min.x) min.x = v.x;
if (v.y < min.y) min.y = v.y;
if (v.x > max.x) max.x = v.x;
if (v.y > max.y) max.y = v.y;
}
}
float ratio_width = (max.x - min.x) / Camera.main.pixelWidth;
float ratio_height = (max.y - min.y) / Camera.main.pixelHeight;
float ratio = (ratio_width > ratio_height) ? ratio_width : ratio_height;
if (ratio > 1.0f) ratio = 1.0f;
return ratio;
}
private float ratio_of_distance(float distance0)
{
Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
foreach (Component child in allBasicRenderers)
{
Renderer rend = (Renderer)child;
Vector3 center = rend.bounds.center;
float radius = rend.bounds.extents.magnitude;
Vector3[] six_points = new Vector3[6];
six_points[0] = new Vector3(center.x - radius, center.y, center.z);
six_points[1] = new Vector3(center.x + radius, center.y, center.z);
six_points[2] = new Vector3(center.x, center.y - radius, center.z);
six_points[3] = new Vector3(center.x, center.y + radius, center.z);
six_points[4] = new Vector3(center.x, center.y, center.z - radius);
six_points[5] = new Vector3(center.x, center.y, center.z + radius);
foreach (Vector3 v in six_points)
{
if (v.x < min.x) min.x = v.x;
if (v.y < min.y) min.y = v.y;
if (v.z < min.z) min.z = v.z;
if (v.x > max.x) max.x = v.x;
if (v.y > max.y) max.y = v.y;
if (v.z > max.z) max.z = v.z;
}
}
Vector3 average_position = (min + max) * 0.5f;
float distance = Vector3.Distance(Camera.main.transform.position, average_position);
float ratio = 1.0f - distance / distance0;
if (ratio < 0.0f) ratio = 0.0f;
return ratio;
}
// Update is called once per frame
void Update()
{
if (progressiveMesh)
{
currentTimeToInterval -= Time.deltaTime;
// time out
if (currentTimeToInterval <= 0.0f)
{
// detect if the game object is visible
bool visable = false;
if (!culled)
{
allBasicRenderers = (Component[])(gameObject.GetComponentsInChildren(typeof(Renderer)));
foreach (Component child in allBasicRenderers)
{
if (((Renderer)child).isVisible) visable = true;
break;
}
}
// we only change levels when the game object had been culled by ourselves or is visable
if (culled || visable)
{
float ratio = 0.0f;
// we only calculate ratio of screen when the main camera is active in hierarchy
if (Camera.main != null && Camera.main.gameObject != null && Camera.main.gameObject.activeInHierarchy)
{
allBasicRenderers = (Component[])(gameObject.GetComponentsInChildren(typeof(Renderer)));
if (lod_strategy == 0) ratio = ratio_of_screen();
if (lod_strategy == 1) ratio = ratio_of_distance(disappear_distance);
}
// you may change cull condition here
if (never_cull == false && ratio < cull_ratio)
{
// cull the game object
if (!culled)
{
// cull me
allBasicRenderers = (Component[])(gameObject.GetComponentsInChildren(typeof(Renderer)));
foreach (Component child in allBasicRenderers)
{
((Renderer)child).enabled = false;
}
culled = true;
}
}
else
{
// show the game object
if (culled)
{
// show me
allBasicRenderers = (Component[])(gameObject.GetComponentsInChildren(typeof(Renderer)));
foreach (Component child in allBasicRenderers)
{
((Renderer)child).enabled = true;
}
culled = false;
}
// get lod count
int max_lod_count = progressiveMesh.triangles[0];
// set triangle list according to current lod
int lod = (int)((1.0f - ratio) * max_lod_count);
// clamp the value
if (lod > max_lod_count - 1) lod = max_lod_count - 1;
// lod changed
if (current_lod != lod)
{
int total_triangles_count = 0;
int counter = 0;
foreach (Component child in allFilters)
{
string uuid = mesh_uuids[counter];
int mesh_index = Array.IndexOf(progressiveMesh.uuids, uuid);
// the mesh is in the progressive mesh list
if (mesh_index != -1)
{
int clamp_lod = lod;
// clamp to valid range
if (clamp_lod < mesh_lod_range[mesh_index * 2]) clamp_lod = mesh_lod_range[mesh_index * 2];
if (clamp_lod > mesh_lod_range[mesh_index * 2 + 1]) clamp_lod = mesh_lod_range[mesh_index * 2 + 1];
// because other instances may have terminated, we need to check if lod meshes is null.
if (progressiveMesh.lod_meshes != null && progressiveMesh.lod_meshes.ContainsKey(uuid))
{
Lod_Mesh lod_mesh = ((Lod_Mesh[])progressiveMesh.lod_meshes[uuid])[clamp_lod];
((MeshFilter)child).sharedMesh = lod_mesh.mesh;
total_triangles_count += lod_mesh.triangle_count;
}
}
counter++;
}
foreach (Component child in allRenderers)
{
string uuid = mesh_uuids[counter];
int mesh_index = Array.IndexOf(progressiveMesh.uuids, uuid);
// the mesh is in the progressive mesh list
if (mesh_index != -1)
{
int clamp_lod = lod;
// clamp to valid range
if (clamp_lod < mesh_lod_range[mesh_index * 2]) clamp_lod = mesh_lod_range[mesh_index * 2];
if (clamp_lod > mesh_lod_range[mesh_index * 2 + 1]) clamp_lod = mesh_lod_range[mesh_index * 2 + 1];
// because other instances may have terminated, we need to check if lod meshes is null.
if (progressiveMesh.lod_meshes != null && progressiveMesh.lod_meshes.ContainsKey(uuid))
{
Lod_Mesh lod_mesh = ((Lod_Mesh[])progressiveMesh.lod_meshes[uuid])[clamp_lod];
((SkinnedMeshRenderer)child).sharedMesh = lod_mesh.mesh;
total_triangles_count += lod_mesh.triangle_count;
}
}
counter++;
}
// update read only status
if (lodHint) lodHint.text = "Level Of Detail: " + lod.ToString();
if (triangleHint) triangleHint.text = "Triangle Count: " + (total_triangles_count / 3).ToString();
current_lod = lod;
}
}
}
if (fpsHint)
{
int fps = Mathf.RoundToInt(1.0f / Time.smoothDeltaTime);
fpsHint.text = "FPS: " + fps.ToString();
}
//reset timer
currentTimeToInterval = updateInterval + (UnityEngine.Random.value + 0.5f) * currentTimeToInterval;
}
}
}
public int get_triangles_count_from_progressive_mesh(int lod0, int mesh_count0)
{
int counter = 0;
int triangle_count = 0;
// max lod count
int max_lod_count = progressiveMesh.triangles[triangle_count];
triangle_count++;
for (int lod = 0; lod < max_lod_count; lod++)
{
// max mesh count
int max_mesh_count = progressiveMesh.triangles[triangle_count];
triangle_count++;
for (int mesh_count = 0; mesh_count < max_mesh_count; mesh_count++)
{
// max sub mesh count
int max_sub_mesh_count = progressiveMesh.triangles[triangle_count];
triangle_count++;
for (int mat = 0; mat < max_sub_mesh_count; mat++)
{
// max triangle count
int max_triangle_count = progressiveMesh.triangles[triangle_count];
triangle_count++;
// here it is
if (lod == lod0 && mesh_count == mesh_count0)
{
counter += max_triangle_count;
}
// triangle list count
triangle_count += max_triangle_count;
}
}
}
return counter / 3;
}
private int[] get_triangles_from_progressive_mesh(int lod0, int mesh_count0, int mat0)
{
int triangle_count = 0;
// max lod count
int max_lod_count = progressiveMesh.triangles[triangle_count];
triangle_count++;
for (int lod = 0; lod < max_lod_count; lod++)
{
// max mesh count
int max_mesh_count = progressiveMesh.triangles[triangle_count];
triangle_count++;
for (int mesh_count = 0; mesh_count < max_mesh_count; mesh_count++)
{
// max sub mesh count
int max_sub_mesh_count = progressiveMesh.triangles[triangle_count];
triangle_count++;
for (int mat = 0; mat < max_sub_mesh_count; mat++)
{
// max triangle count
int max_triangle_count = progressiveMesh.triangles[triangle_count];
triangle_count++;
// here it is
if (lod == lod0 && mesh_count == mesh_count0 && mat == mat0)
{
int[] new_triangles = new int[max_triangle_count];
Array.Copy(progressiveMesh.triangles, triangle_count, new_triangles, 0, max_triangle_count);
return new_triangles;
}
// triangle list count
triangle_count += max_triangle_count;
}
}
}
return null;
}
private void set_triangles(Mesh mesh, string uuid, int lod)
{
int mesh_index = Array.IndexOf(progressiveMesh.uuids, uuid);
// the mesh is in the progressive mesh list
if (mesh_index != -1)
{
for (int mat = 0; mat < mesh.subMeshCount; mat++)
{
int[] triangle_list = get_triangles_from_progressive_mesh(lod, mesh_index, mat);
mesh.SetTriangles(triangle_list, mat);
}
}
}
private void shrink_mesh(Mesh mesh)
{
// get all origin data
Vector3[] origin_vertices = mesh.vertices;
Vector3[] vertices = null;
if (origin_vertices != null && origin_vertices.Length > 0) vertices = new Vector3[origin_vertices.Length];
BoneWeight[] origin_boneWeights = mesh.boneWeights;
BoneWeight[] boneWeights = null;
if (origin_boneWeights != null && origin_boneWeights.Length > 0) boneWeights = new BoneWeight[origin_boneWeights.Length];
Color[] origin_colors = mesh.colors;
Color[] colors = null;
if (origin_colors != null && origin_colors.Length > 0) colors = new Color[origin_colors.Length];
Color32[] origin_colors32 = mesh.colors32;
Color32[] colors32 = null;
if (origin_colors32 != null && origin_colors32.Length > 0) colors32 = new Color32[origin_colors32.Length];
Vector4[] origin_tangents = mesh.tangents;
Vector4[] tangents = null;
if (origin_tangents != null && origin_tangents.Length > 0) tangents = new Vector4[origin_tangents.Length];
Vector3[] origin_normals = mesh.normals;
Vector3[] normals = null;
if (origin_normals != null && origin_normals.Length > 0) normals = new Vector3[origin_normals.Length];
Vector2[] origin_uv = mesh.uv;
Vector2[] uv = null;
if (origin_uv != null && origin_uv.Length > 0) uv = new Vector2[origin_uv.Length];
Vector2[] origin_uv2 = mesh.uv2;
Vector2[] uv2 = null;
if (origin_uv2 != null && origin_uv2.Length > 0) uv2 = new Vector2[origin_uv2.Length];
int[][] origin_triangles = new int[mesh.subMeshCount][];
for (int i = 0; i < mesh.subMeshCount; i++)
{
origin_triangles[i] = mesh.GetTriangles(i);
}
// make permutation
Dictionary<int, int> imap = new Dictionary<int, int>();
int vertex_count = 0;
for (int i = 0; i < mesh.subMeshCount; i++)
{
int[] triangles = mesh.GetTriangles(i);
for (int j = 0; j < triangles.Length; j += 3)
{
if (!imap.ContainsKey(triangles[j]))
{
if (vertices != null) vertices[vertex_count] = origin_vertices[triangles[j]];
if (boneWeights != null) boneWeights[vertex_count] = origin_boneWeights[triangles[j]];
if (colors != null) colors[vertex_count] = origin_colors[triangles[j]];
if (colors32 != null) colors32[vertex_count] = origin_colors32[triangles[j]];
if (tangents != null) tangents[vertex_count] = origin_tangents[triangles[j]];
if (normals != null) normals[vertex_count] = origin_normals[triangles[j]];
if (uv != null) uv[vertex_count] = origin_uv[triangles[j]];
if (uv2 != null) uv2[vertex_count] = origin_uv2[triangles[j]];
imap.Add(triangles[j], vertex_count);
vertex_count++;
}
if (!imap.ContainsKey(triangles[j + 1]))
{
if (vertices != null) vertices[vertex_count] = origin_vertices[triangles[j + 1]];
if (boneWeights != null) boneWeights[vertex_count] = origin_boneWeights[triangles[j + 1]];
if (colors != null) colors[vertex_count] = origin_colors[triangles[j + 1]];
if (colors32 != null) colors32[vertex_count] = origin_colors32[triangles[j + 1]];
if (tangents != null) tangents[vertex_count] = origin_tangents[triangles[j + 1]];
if (normals != null) normals[vertex_count] = origin_normals[triangles[j + 1]];
if (uv != null) uv[vertex_count] = origin_uv[triangles[j + 1]];
if (uv2 != null) uv2[vertex_count] = origin_uv2[triangles[j + 1]];
imap.Add(triangles[j + 1], vertex_count);
vertex_count++;
}
if (!imap.ContainsKey(triangles[j + 2]))
{
if (vertices != null) vertices[vertex_count] = origin_vertices[triangles[j + 2]];
if (boneWeights != null) boneWeights[vertex_count] = origin_boneWeights[triangles[j + 2]];
if (colors != null) colors[vertex_count] = origin_colors[triangles[j + 2]];
if (colors32 != null) colors32[vertex_count] = origin_colors32[triangles[j + 2]];
if (tangents != null) tangents[vertex_count] = origin_tangents[triangles[j + 2]];
if (normals != null) normals[vertex_count] = origin_normals[triangles[j + 2]];
if (uv != null) uv[vertex_count] = origin_uv[triangles[j + 2]];
if (uv2 != null) uv2[vertex_count] = origin_uv2[triangles[j + 2]];
imap.Add(triangles[j + 2], vertex_count);
vertex_count++;
}
}
}
// set data back to mesh
mesh.Clear(false);
if (vertices != null)
{
Vector3[] new_vertices = new Vector3[vertex_count];
Array.Copy(vertices, new_vertices, vertex_count);
mesh.vertices = new_vertices;
}
if (boneWeights != null)
{
BoneWeight[] new_boneWeights = new BoneWeight[vertex_count];
Array.Copy(boneWeights, new_boneWeights, vertex_count);
mesh.boneWeights = new_boneWeights;
}
if (colors != null)
{
Color[] new_colors = new Color[vertex_count];
Array.Copy(colors, new_colors, vertex_count);
mesh.colors = new_colors;
}
if (colors32 != null)
{
Color32[] new_colors32 = new Color32[vertex_count];
Array.Copy(colors32, new_colors32, vertex_count);
mesh.colors32 = new_colors32;
}
if (tangents != null)
{
Vector4[] new_tangents = new Vector4[vertex_count];
Array.Copy(tangents, new_tangents, vertex_count);
mesh.tangents = new_tangents;
}
if (normals != null)
{
Vector3[] new_normals = new Vector3[vertex_count];
Array.Copy(normals, new_normals, vertex_count);
mesh.normals = new_normals;
}
if (uv != null)
{
Vector2[] new_uv = new Vector2[vertex_count];
Array.Copy(uv, new_uv, vertex_count);
mesh.uv = new_uv;
}
if (uv2 != null)
{
Vector2[] new_uv2 = new Vector2[vertex_count];
Array.Copy(uv2, new_uv2, vertex_count);
mesh.uv2 = new_uv2;
}
mesh.subMeshCount = origin_triangles.Length;
for (int i = 0; i < mesh.subMeshCount; i++)
{
int[] new_triangles = new int[origin_triangles[i].Length];
for (int j = 0; j < new_triangles.Length; j += 3)
{
new_triangles[j] = (int)imap[origin_triangles[i][j]];
new_triangles[j + 1] = (int)imap[origin_triangles[i][j + 1]];
new_triangles[j + 2] = (int)imap[origin_triangles[i][j + 2]];
}
mesh.SetTriangles(new_triangles, i);
}
// refresh normals and bounds
//mesh.RecalculateNormals();
//mesh.RecalculateBounds();
}
private string get_uuid_from_mesh(Mesh mesh)
{
string uuid = mesh.name + "_" + mesh.vertexCount.ToString() + "_" + mesh.subMeshCount.ToString();
for (int i = 0; i < mesh.subMeshCount; ++i)
{
uuid += "_" + mesh.GetIndexCount(i).ToString();
}
return uuid;
}
private void create_default_mesh_lod_range()
{
int max_lod_count = progressiveMesh.triangles[0];
int mesh_count = progressiveMesh.triangles[1];
mesh_lod_range = new int[mesh_count * 2];
for (int i = 0; i < mesh_count; i++)
{
mesh_lod_range[i * 2] = 0;
mesh_lod_range[i * 2 + 1] = max_lod_count - 1;
}
}
private void get_all_meshes()
{
if (!working)
{
int max_lod_count = progressiveMesh.triangles[0];
if (mesh_lod_range == null || mesh_lod_range.Length == 0)
{
create_default_mesh_lod_range();
}
if (allFilters == null && allRenderers == null)
{
allFilters = (Component[])(gameObject.GetComponentsInChildren(typeof(MeshFilter)));
allRenderers = (Component[])(gameObject.GetComponentsInChildren(typeof(SkinnedMeshRenderer)));
}
int mesh_count = allFilters.Length + allRenderers.Length;
if (mesh_count > 0)
{
shared_meshes = new Mesh[mesh_count];
mesh_uuids = new string[mesh_count];
int counter = 0;
foreach (Component child in allFilters)
{
string uuid = get_uuid_from_mesh(((MeshFilter)child).sharedMesh);
mesh_uuids[counter] = uuid;
// store original shared mesh
shared_meshes[counter] = ((MeshFilter)child).sharedMesh;
// mesh lods map does not exist
if (progressiveMesh.lod_meshes == null)
{
progressiveMesh.lod_meshes = new Dictionary<string, Lod_Mesh[]>();
}
// create mesh lods if it does not exist
if (!progressiveMesh.lod_meshes.ContainsKey(uuid))
{
int mesh_index = Array.IndexOf(progressiveMesh.uuids, uuid);
if (mesh_index != -1)
{
Lod_Mesh[] lod_meshes = new Lod_Mesh[max_lod_count];
for (int lod = 0; lod < max_lod_count; lod++)
{
lod_meshes[lod] = new Lod_Mesh();
lod_meshes[lod].mesh = Instantiate(((MeshFilter)child).sharedMesh);
set_triangles(lod_meshes[lod].mesh, uuid, lod);
// remove unused vertices
if (lod_meshes[lod].mesh.blendShapeCount == 0)
{
shrink_mesh(lod_meshes[lod].mesh);
}
#if UNITY_EDITOR
MeshUtility.Optimize(lod_meshes[lod].mesh);
#elif UNITY_2019_1_OR_NEWER
lod_meshes[lod].mesh.Optimize();
#endif
lod_meshes[lod].triangle_count = lod_meshes[lod].mesh.triangles.Length;
}
progressiveMesh.lod_meshes.Add(uuid, lod_meshes);
}
}
counter++;
}
foreach (Component child in allRenderers)
{
string uuid = get_uuid_from_mesh(((SkinnedMeshRenderer)child).sharedMesh);
mesh_uuids[counter] = uuid;
// store original shared mesh
shared_meshes[counter] = ((SkinnedMeshRenderer)child).sharedMesh;
// mesh lods map does not exist
if (progressiveMesh.lod_meshes == null)
{
progressiveMesh.lod_meshes = new Dictionary<string, Lod_Mesh[]>();
}
// create mesh lods if it does not exist
if (!progressiveMesh.lod_meshes.ContainsKey(uuid))
{
int mesh_index = Array.IndexOf(progressiveMesh.uuids, uuid);
if (mesh_index != -1)
{
Lod_Mesh[] lod_meshes = new Lod_Mesh[max_lod_count];
for (int lod = 0; lod < max_lod_count; lod++)
{
lod_meshes[lod] = new Lod_Mesh();
lod_meshes[lod].mesh = Instantiate(((SkinnedMeshRenderer)child).sharedMesh);
set_triangles(lod_meshes[lod].mesh, uuid, lod);
// remove unused vertices
if (lod_meshes[lod].mesh.blendShapeCount == 0)
{
shrink_mesh(lod_meshes[lod].mesh);
}
#if UNITY_EDITOR
MeshUtility.Optimize(lod_meshes[lod].mesh);
#elif UNITY_2019_1_OR_NEWER
lod_meshes[lod].mesh.Optimize();
#endif
lod_meshes[lod].triangle_count = lod_meshes[lod].mesh.triangles.Length;
}
progressiveMesh.lod_meshes.Add(uuid, lod_meshes);
}
}
counter++;
}
}
// get all renderers
allBasicRenderers = (Component[])(gameObject.GetComponentsInChildren(typeof(Renderer)));
// We use random value to spread the update moment in range [0, updateInterval]
currentTimeToInterval = UnityEngine.Random.value * updateInterval;
// init current lod
current_lod = -1;
working = true;
}
}
public void reset_all_parameters()
{
mesh_lod_range = null;
never_cull = true;
lod_strategy = 1;
cull_ratio = 0.1f;
disappear_distance = 250.0f;
updateInterval = 0.25f;
}
private void clean_all()
{
if (working)
{
int mesh_count = allFilters.Length + allRenderers.Length;
if (mesh_count > 0)
{
int counter = 0;
foreach (Component child in allFilters)
{
// restore original shared mesh
((MeshFilter)child).sharedMesh = shared_meshes[counter];
counter++;
}
foreach (Component child in allRenderers)
{
// restore original shared mesh
((SkinnedMeshRenderer)child).sharedMesh = shared_meshes[counter];
counter++;
}
}
shared_meshes = null;
allBasicRenderers = null;
allFilters = null;
allRenderers = null;
progressiveMesh.lod_meshes = null;
working = false;
}
}
void OnEnable()
{
Awake();
Start();
}
void OnDisable()
{
clean_all();
}
void OnDestroy()
{
clean_all();
}
}
}