Esempio n. 1
0
        public void Simplify(WMesh inputMesh, WMesh outputMesh, float quality)
        {
            var enableLogging = false;
            int totalTriangleCount;
            var sourceMesh          = ToMeshDecimatorMesh(inputMesh, out totalTriangleCount);
            int targetTriangleCount = Mathf.CeilToInt(totalTriangleCount * quality);

            var algorithm = MeshDecimation.CreateAlgorithm(Algorithm.Default);

            DecimationAlgorithm.StatusReportCallback statusCallback = (iteration, tris, currentTris, targetTris) =>
            {
                Debug.LogFormat("Iteration {0}: tris {1} current {2} target {3}", iteration, tris, currentTris, targetTris);
            };

            if (enableLogging)
            {
                algorithm.StatusReport += statusCallback;
            }

            var destMesh = MeshDecimation.DecimateMesh(algorithm, sourceMesh, targetTriangleCount);

            if (enableLogging)
            {
                algorithm.StatusReport -= statusCallback;
            }

            FromMeshDecimatorMesh(destMesh, false, ref outputMesh);
        }
Esempio n. 2
0
        public static WorkingMesh ToWorkingMesh(this Mesh mesh)
        {
            var wm = new WorkingMesh();

            mesh.ApplyToWorkingMesh(wm);
            return(wm);
        }
Esempio n. 3
0
        IEnumerator Simplify(WorkingMesh inputMesh, WorkingMesh outputMesh, float quality)
        {
            Renderer renderer = null;

            MonoBehaviourHelper.ExecuteOnMainThread(() =>
            {
                var go = EditorUtility.CreateGameObjectWithHideFlags("Temp", HideFlags.HideAndDontSave,
                                                                     typeof(MeshRenderer), typeof(MeshFilter));
                var mf   = go.GetComponent <MeshFilter>();
                var mesh = new Mesh();
                inputMesh.ApplyToMesh(mesh);
                mf.sharedMesh       = mesh;
                renderer            = go.GetComponent <MeshRenderer>();
                var material        = new Material(Shader.Find("Standard"));
                var sharedMaterials = new Material[mesh.subMeshCount];
                for (int i = 0; i < mesh.subMeshCount; i++)
                {
                    sharedMaterials[i] = material;
                }
                renderer.sharedMaterials = sharedMaterials;
                renderer.enabled         = false;
            });

            var settings = new InstaLODOptimizeSettings(quality);

            settings.PercentTriangles = quality;
            var nativeMeshSettings = new InstaLODNativeMeshOperationSettings(true);

            nativeMeshSettings.hideSourceGameObjects = false;


            while (InstaLODNative.currentMeshOperationState != null)
            {
                yield return(null);
            }

            MonoBehaviourHelper.ExecuteOnMainThread(() =>
            {
                EditorWindow.GetWindow <InstaLODToolkitWindow>(); // Necessary for background processing
                InstaLODNative.Optimize(new List <Renderer>()
                {
                    renderer
                }, settings, nativeMeshSettings);
                Selection.activeGameObject =
                    null; // Necessary to avoid errors from InstaLOD trying to add settings component to imported model
            });

            while (InstaLODNative.currentMeshOperationState != null)
            {
                yield return(null);
            }

            MonoBehaviourHelper.ExecuteOnMainThread(() =>
            {
                var mf = renderer.GetComponent <MeshFilter>();
                mf.sharedMesh.ApplyToWorkingMesh(outputMesh);
                UnityObject.DestroyImmediate(mf.gameObject);
            });
        }
Esempio n. 4
0
        public static WorkingMesh ToWorkingMesh(this Mesh mesh, Allocator allocator)
        {
            var bindposes = mesh.bindposes;
            var wm        = new WorkingMesh(allocator, mesh.vertexCount, mesh.GetTriangleCount(), mesh.subMeshCount, bindposes.Length);

            mesh.ApplyToWorkingMesh(ref wm, bindposes);

            return(wm);
        }
Esempio n. 5
0
        static void GenerateMeshLOD(MeshLOD meshLOD, HashSet <int> preprocessMeshes)
        {
            // A NOP to make sure we have an instance before launching into threads that may need to execute on the main thread
            MonoBehaviourHelper.ExecuteOnMainThread(() => { });

            WorkingMesh inputMesh   = null;
            var         inputMeshID = meshLOD.inputMesh.GetInstanceID();

            if (!preprocessMeshes.Contains(inputMeshID))
            {
                inputMesh = meshLOD.inputMesh.ToWorkingMesh();
            }

            var meshSimplifier = (IMeshSimplifier)Activator.CreateInstance(meshLOD.meshSimplifierType);
            var worker         = new BackgroundWorker();

            worker.DoWork += (sender, args) =>
            {
                // If this mesh is dependent on another mesh, then let it complete first
                if (inputMesh == null)
                {
                    while (preprocessMeshes.Contains(inputMeshID))
                    {
                        Thread.Sleep(100);
                    }

                    MonoBehaviourHelper.ExecuteOnMainThread(() => inputMesh = meshLOD.inputMesh.ToWorkingMesh());
                }

                var outputMesh = new WorkingMesh();
#if UNITY_2017_3_OR_NEWER
                outputMesh.indexFormat = inputMesh.indexFormat;
#endif
                meshSimplifier.Simplify(inputMesh, outputMesh, meshLOD.quality, () =>
                {
                    var outMesh = meshLOD.outputMesh;
                    Debug.Log("Completed LOD " + outMesh.name);
                    outputMesh.name = outMesh.name;
                    outputMesh.ApplyToMesh(outMesh);
                    outMesh.RecalculateBounds();

                    var outputMeshID = outMesh.GetInstanceID();
                    if (preprocessMeshes.Remove(outputMeshID))
                    {
                        Debug.Log("Pre-process mesh complete: " + outputMeshID);
                    }
                });;
            };

            worker.RunWorkerAsync();
        }
Esempio n. 6
0
 // Taking bindposes optional parameter is ugly, but saves an additional array allocation if it was already
 // accessed to get the length
 public static void ApplyToWorkingMesh(this Mesh mesh, ref WorkingMesh wm, Matrix4x4[] bindposes = null)
 {
     wm.indexFormat  = mesh.indexFormat;
     wm.vertices     = mesh.vertices;
     wm.normals      = mesh.normals;
     wm.tangents     = mesh.tangents;
     wm.uv           = mesh.uv;
     wm.uv2          = mesh.uv2;
     wm.uv3          = mesh.uv3;
     wm.uv4          = mesh.uv4;
     wm.colors       = mesh.colors;
     wm.boneWeights  = mesh.boneWeights;
     wm.bindposes    = bindposes ?? mesh.bindposes;
     wm.subMeshCount = mesh.subMeshCount;
     for (int i = 0; i < mesh.subMeshCount; i++)
     {
         wm.SetTriangles(mesh.GetTriangles(i), i);
     }
     wm.name   = mesh.name;
     wm.bounds = mesh.bounds;
 }
Esempio n. 7
0
        IEnumerator Simplify(Mesh inputMesh, Mesh outputMesh, float quality)
        {
            var meshSimplifier = new MeshSimplifier();

            meshSimplifier.Vertices = inputMesh.vertices;
            meshSimplifier.Normals  = inputMesh.normals;
            meshSimplifier.Tangents = inputMesh.tangents;
            meshSimplifier.UV1      = inputMesh.uv;
            meshSimplifier.UV2      = inputMesh.uv2;
            meshSimplifier.UV3      = inputMesh.uv3;
            meshSimplifier.UV4      = inputMesh.uv4;
            meshSimplifier.Colors   = inputMesh.colors;

            var triangles = new int[inputMesh.subMeshCount][];

            for (var submesh = 0; submesh < inputMesh.subMeshCount; submesh++)
            {
                triangles[submesh] = inputMesh.GetTriangles(submesh);
            }

            meshSimplifier.AddSubMeshTriangles(triangles);

            meshSimplifier.SimplifyMesh(quality);

            outputMesh.vertices     = meshSimplifier.Vertices;
            outputMesh.normals      = meshSimplifier.Normals;
            outputMesh.tangents     = meshSimplifier.Tangents;
            outputMesh.uv           = meshSimplifier.UV1;
            outputMesh.uv2          = meshSimplifier.UV2;
            outputMesh.uv3          = meshSimplifier.UV3;
            outputMesh.uv4          = meshSimplifier.UV4;
            outputMesh.colors       = meshSimplifier.Colors;
            outputMesh.subMeshCount = meshSimplifier.SubMeshCount;
            for (var submesh = 0; submesh < outputMesh.subMeshCount; submesh++)
            {
                outputMesh.SetTriangles(meshSimplifier.GetSubMeshTriangles(submesh), submesh);
            }

            yield break;
        }
Esempio n. 8
0
        public static void ApplyToWorkingMesh(this Mesh mesh, WorkingMesh wm)
        {
#if UNITY_2017_3_OR_NEWER
            wm.indexFormat = mesh.indexFormat;
#endif
            wm.vertices     = mesh.vertices;
            wm.normals      = mesh.normals;
            wm.tangents     = mesh.tangents;
            wm.uv           = mesh.uv;
            wm.uv2          = mesh.uv2;
            wm.uv3          = mesh.uv3;
            wm.uv4          = mesh.uv4;
            wm.colors       = mesh.colors;
            wm.boneWeights  = mesh.boneWeights;
            wm.bindposes    = mesh.bindposes;
            wm.subMeshCount = mesh.subMeshCount;
            for (int i = 0; i < mesh.subMeshCount; i++)
            {
                wm.SetTriangles(mesh.GetTriangles(i), i);
            }
            wm.name   = mesh.name;
            wm.bounds = mesh.bounds;
        }
Esempio n. 9
0
        public JobHandle Generate()
        {
            // A NOP to make sure we have an instance before launching into threads that may need to execute on the main thread
            MonoBehaviourHelper.ExecuteOnMainThread(() => { });

            var job       = default(T);
            var inputMesh = InputMesh;

            job.InputMesh = inputMesh.ToWorkingMesh(Allocator.Persistent);
            job.Quality   = Quality;
            // Allocate a persistent working mesh for output, so that we can apply it after the job completes (i.e. memory
            // allocated in a job is freed when the job completes)
            var workingMesh = new WorkingMesh(Allocator.Persistent, inputMesh.vertexCount, inputMesh.GetTriangleCount(),
                                              inputMesh.subMeshCount, inputMesh.blendShapeCount);

            workingMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
            job.OutputMesh          = workingMesh;

            var jobHandle = job.Schedule();

            MonoBehaviourHelper.StartCoroutine(UpdateMesh(jobHandle, job));

            return(jobHandle);
        }
Esempio n. 10
0
        public void Simplify(WorkingMesh inputMesh, WorkingMesh outputMesh, float quality)
        {
            var isMainThread = MonoBehaviourHelper.IsMainThread();

            Renderer renderer = null;

            UnityCloudJob job     = null;
            string        jobName = null;

            var assembly     = typeof(SharedData).Assembly;
            var cloudJobType = assembly.GetType("Simplygon.Cloud.Yoda.IntegrationClient.CloudJob");
            var jobNameField = cloudJobType.GetField("name", BindingFlags.NonPublic | BindingFlags.Instance);

            lock (executionLock)
            {
                const int kSimultaneousJobs = 4;
                //var processSubscriptionRestrictionsType = assembly.GetType("Simplygon.Cloud.Yoda.Client.ProcessSubscriptionRestrictions23");
                //var simultaneousJobsProperty = processSubscriptionRestrictionsType.GetProperty("SimultaneousJobs");
                //var accountType = assembly.GetType("Simplygon.Cloud.Yoda.Client.User23");
                //var processSubscriptionsRestrictionsProperty = accountType.GetProperty("ProcessSubscriptionRestrictions");
                //var processSubscriptionRestrictions = processSubscriptionsRestrictionsProperty.GetValue(SharedData.Instance.Account, null);
                //var simultaneousJobs = (int)simultaneousJobsProperty.GetValue(processSubscriptionRestrictions, null);

                while (SharedData.Instance.GeneralManager.JobManager.ProcessingJobCount >= kSimultaneousJobs)
                {
                    if (!isMainThread)
                    {
                        Thread.Sleep(1000);
                    }
                }

                MonoBehaviourHelper.ExecuteOnMainThread(() =>
                {
                    var go   = EditorUtility.CreateGameObjectWithHideFlags("Temp", HideFlags.HideAndDontSave, typeof(MeshRenderer), typeof(MeshFilter));
                    var mf   = go.GetComponent <MeshFilter>();
                    var mesh = new Mesh();
                    inputMesh.ApplyToMesh(mesh);
                    mf.sharedMesh       = mesh;
                    renderer            = go.GetComponent <MeshRenderer>();
                    var material        = new Material(Shader.Find("Standard"));
                    var sharedMaterials = new Material[mesh.subMeshCount];
                    for (int i = 0; i < mesh.subMeshCount; i++)
                    {
                        sharedMaterials[i] = material;
                    }
                    renderer.sharedMaterials = sharedMaterials;
                    renderer.enabled         = false;

                    EditorWindow.GetWindow <Window>(); // Must be visible for background processing

                    SharedData.Instance.Settings.SetDownloadAssetsAutomatically(true);

                    var lodChainProperty = typeof(SharedData).GetProperty("LODChain");
                    var lodChainList     = lodChainProperty.GetValue(SharedData.Instance, null) as IList;
                    var lodChain         = lodChainList[0];

                    var processNodeType   = assembly.GetType("Simplygon.SPL.v80.Node.ProcessNode");
                    var processorProperty = processNodeType.GetProperty("Processor");
                    var processor         = processorProperty.GetValue(lodChain, null);

                    var reductionProcessorType    = assembly.GetType("Simplygon.SPL.v80.Processor.ReductionProcessor");
                    var reductionSettingsProperty = reductionProcessorType.GetProperty("ReductionSettings");
                    var reductionSettingsType     = assembly.GetType("Simplygon.SPL.v80.Settings.ReductionSettings");
                    var reductionSettings         = reductionSettingsProperty.GetValue(processor, null);

                    var triangleRatioProperty = reductionSettingsType.GetProperty("TriangleRatio");
                    triangleRatioProperty.SetValue(reductionSettings, quality, null);

                    jobName        = Path.GetRandomFileName().Replace(".", string.Empty);
                    var prefabList = PrefabUtilityEx.GetPrefabsForSelection(new List <GameObject>()
                    {
                        go
                    });
                    var generalManager = SharedData.Instance.GeneralManager;
                    generalManager.CreateJob(jobName, "myPriority", prefabList, () =>
                    {
                        foreach (var j in generalManager.JobManager.Jobs)
                        {
                            var name = (string)jobNameField.GetValue(j.CloudJob);
                            if (name == jobName)
                            {
                                job = j;
                            }
                        }
                    });
                });

                while (job == null)
                {
                    if (!isMainThread)
                    {
                        Thread.Sleep(100);
                    }
                }
            }

            while (string.IsNullOrEmpty(job.AssetDirectory))
            {
                if (!isMainThread)
                {
                    Thread.Sleep(100);
                }
            }

            MonoBehaviourHelper.ExecuteOnMainThread(() =>
            {
                var customDataType            = assembly.GetType("Simplygon.Cloud.Yoda.IntegrationClient.CloudJob+CustomData");
                var pendingFolderNameProperty = customDataType.GetProperty("UnityPendingLODFolderName");
                var jobCustomDataProperty     = cloudJobType.GetProperty("JobCustomData");
                var jobCustomData             = jobCustomDataProperty.GetValue(job.CloudJob, null);
                var jobFolderName             = pendingFolderNameProperty.GetValue(jobCustomData, null) as string;

                var lodAssetDir = "Assets/LODs/" + job.AssetDirectory;
                var mesh        = AssetDatabase.LoadAssetAtPath <Mesh>(string.Format("{0}/{1}_LOD1.prefab", lodAssetDir, jobName));
                mesh.ApplyToWorkingMesh(ref outputMesh);

                //job.CloudJob.StateHandler.RequestJobDeletion();
                AssetDatabaseEx.DeletePendingLODFolder(jobFolderName);
                AssetDatabase.DeleteAsset(lodAssetDir);

                UnityObject.DestroyImmediate(renderer.gameObject);
            });
        }
Esempio n. 11
0
 public void Simplify(WorkingMesh inputMesh, WorkingMesh outputMesh, float quality, Action completeAction)
 {
     SimplifierRunner.instance.EnqueueSimplification(Simplify(inputMesh, outputMesh, quality), completeAction);
 }
Esempio n. 12
0
        static void FromMeshDecimatorMesh(DMesh mesh, bool recalculateNormals, ref WMesh destMesh)
        {
            if (recalculateNormals)
            {
                // If we recalculate the normals, we also recalculate the tangents
                mesh.RecalculateNormals();
                mesh.RecalculateTangents();
            }

            int subMeshCount = mesh.SubMeshCount;
            var newNormals   = FromVector3(mesh.Normals);
            var newTangents  = FromVector4(mesh.Tangents);
            var newUV1       = FromVector2(mesh.UV1);
            var newUV2       = FromVector2(mesh.UV2);
            var newUV3       = FromVector2(mesh.UV3);
            var newUV4       = FromVector2(mesh.UV4);
            var newColors    = FromColor(mesh.Colors);

            //var newBoneWeights = FromSimplifyBoneWeights(mesh.BoneWeights);

            //if (bindposes != null) newMesh.bindposes = bindposes;
            destMesh.subMeshCount = subMeshCount;
            destMesh.vertices     = FromVector3d(mesh.Vertices);
            if (newNormals != null)
            {
                destMesh.normals = newNormals;
            }

            if (newTangents != null)
            {
                destMesh.tangents = newTangents;
            }

            if (newUV1 != null)
            {
                destMesh.uv = newUV1;
            }

            if (newUV2 != null)
            {
                destMesh.uv2 = newUV2;
            }

            if (newUV3 != null)
            {
                destMesh.uv3 = newUV3;
            }

            if (newUV4 != null)
            {
                destMesh.uv4 = newUV4;
            }

            if (newColors != null)
            {
                destMesh.colors = newColors;
            }

            //if (newBoneWeights != null)
            //    newMesh.boneWeights = newBoneWeights;

            for (int i = 0; i < subMeshCount; i++)
            {
                var subMeshIndices = mesh.GetIndices(i);
                destMesh.SetTriangles(subMeshIndices, i);
            }

            destMesh.RecalculateBounds();
        }
Esempio n. 13
0
        DMesh ToMeshDecimatorMesh(WMesh mesh, out int totalTriangleCount)
        {
            var vertices = ToVector3d(mesh.vertices);

            int subMeshCount = mesh.subMeshCount;
            var meshNormals  = mesh.normals;
            var meshTangents = mesh.tangents;
            var meshUV1      = mesh.uv;
            var meshUV2      = mesh.uv2;
            var meshUV3      = mesh.uv3;
            var meshUV4      = mesh.uv4;
            var meshColors   = mesh.colors;

            //var meshBoneWeights = mesh.boneWeights;
            //var meshBindposes = mesh.bindposes;

            totalTriangleCount = 0;
            var meshIndices = new int[subMeshCount][];

            for (int i = 0; i < subMeshCount; i++)
            {
                meshIndices[i]      = mesh.GetTriangles(i);
                totalTriangleCount += meshIndices[i].Length / 3;
            }

            var dmesh = new DMesh(vertices, meshIndices);

            if (meshNormals != null && meshNormals.Length > 0)
            {
                dmesh.Normals = ToVector3(meshNormals);
            }

            if (meshTangents != null && meshTangents.Length > 0)
            {
                dmesh.Tangents = ToVector4(meshTangents);
            }

            if (meshUV1 != null && meshUV1.Length > 0)
            {
                dmesh.UV1 = ToVector2(meshUV1);
            }

            if (meshUV2 != null && meshUV2.Length > 0)
            {
                dmesh.UV2 = ToVector2(meshUV2);
            }

            if (meshUV3 != null && meshUV3.Length > 0)
            {
                dmesh.UV3 = ToVector2(meshUV3);
            }

            if (meshUV4 != null && meshUV4.Length > 0)
            {
                dmesh.UV4 = ToVector2(meshUV4);
            }

            if (meshColors != null && meshColors.Length > 0)
            {
                dmesh.Colors = ToVector4(meshColors);
            }

            //if (meshBoneWeights != null && meshBoneWeights.Length > 0)
            //    dmesh.BoneWeights = ToSimplifyBoneWeights(meshBoneWeights);

            return(dmesh);
        }
Esempio n. 14
0
        IEnumerator Simplify(WorkingMesh inputMesh, WorkingMesh outputMesh, float quality)
        {
            Renderer renderer = null;

            UnityCloudJob job     = null;
            string        jobName = null;

            var assembly     = typeof(SharedData).Assembly;
            var cloudJobType = assembly.GetType("Simplygon.Cloud.Yoda.IntegrationClient.CloudJob");
            var jobNameField = cloudJobType.GetField("name", BindingFlags.NonPublic | BindingFlags.Instance);

            MonoBehaviourHelper.ExecuteOnMainThread(() =>
            {
                var go = EditorUtility.CreateGameObjectWithHideFlags("Temp", HideFlags.HideAndDontSave,
                                                                     typeof(MeshRenderer), typeof(MeshFilter));
                var mf   = go.GetComponent <MeshFilter>();
                var mesh = new Mesh();
                inputMesh.ApplyToMesh(mesh);
                mf.sharedMesh = mesh;
                renderer      = go.GetComponent <MeshRenderer>();

                var sharedMaterials = new Material[mesh.subMeshCount];

                if (Directory.Exists(materialPath) == false)
                {
                    Directory.CreateDirectory(materialPath);
                }

                //For submesh, we should create material asset.
                //otherwise, simplygon will be combine uv of submesh.
                for (int i = 0; i < mesh.subMeshCount; i++)
                {
                    var material  = new Material(Shader.Find("Standard"));
                    material.name = "Material " + i.ToString();

                    AssetDatabase.CreateAsset(material, materialPath + "/" + material.name);

                    sharedMaterials[i] = material;
                }

                renderer.sharedMaterials = sharedMaterials;
                renderer.enabled         = false;

                EditorWindow.GetWindow <Window>(); // Must be visible for background processing

                SharedData.Instance.Settings.SetDownloadAssetsAutomatically(true);

                var lodChainProperty = typeof(SharedData).GetProperty("LODChain");
                var lodChainList     = lodChainProperty.GetValue(SharedData.Instance, null) as IList;
                var lodChain         = lodChainList[0];

                var processNodeType   = assembly.GetType("Simplygon.SPL.v80.Node.ProcessNode");
                var processorProperty = processNodeType.GetProperty("Processor");
                var processor         = processorProperty.GetValue(lodChain, null);

                var reductionProcessorType    = assembly.GetType("Simplygon.SPL.v80.Processor.ReductionProcessor");
                var reductionSettingsProperty = reductionProcessorType.GetProperty("ReductionSettings");
                var reductionSettingsType     = assembly.GetType("Simplygon.SPL.v80.Settings.ReductionSettings");
                var reductionSettings         = reductionSettingsProperty.GetValue(processor, null);

                var triangleRatioProperty = reductionSettingsType.GetProperty("TriangleRatio");
                triangleRatioProperty.SetValue(reductionSettings, quality, null);

                jobName        = Path.GetRandomFileName().Replace(".", string.Empty);
                var prefabList = PrefabUtilityEx.GetPrefabsForSelection(new List <GameObject>()
                {
                    go
                });
                var generalManager = SharedData.Instance.GeneralManager;
                generalManager.CreateJob(jobName, "myPriority", prefabList, () =>
                {
                    foreach (var j in generalManager.JobManager.Jobs)
                    {
                        var name = (string)jobNameField.GetValue(j.CloudJob);
                        if (name == jobName)
                        {
                            job = j;
                        }
                    }
                });
            });

            while (job == null)
            {
                yield return(null);
            }


            while (string.IsNullOrEmpty(job.AssetDirectory))
            {
                yield return(null);
            }

            MonoBehaviourHelper.ExecuteOnMainThread(() =>
            {
                var customDataType            = assembly.GetType("Simplygon.Cloud.Yoda.IntegrationClient.CloudJob+CustomData");
                var pendingFolderNameProperty = customDataType.GetProperty("UnityPendingLODFolderName");
                var jobCustomDataProperty     = cloudJobType.GetProperty("JobCustomData");
                var jobCustomData             = jobCustomDataProperty.GetValue(job.CloudJob, null);
                var jobFolderName             = pendingFolderNameProperty.GetValue(jobCustomData, null) as string;

                var lodAssetDir = lodPath + job.AssetDirectory;
                var mesh        = AssetDatabase.LoadAssetAtPath <Mesh>(string.Format("{0}/{1}_LOD1.prefab", lodAssetDir,
                                                                                     jobName));
                mesh.ApplyToWorkingMesh(outputMesh);

                //job.CloudJob.StateHandler.RequestJobDeletion();
                AssetDatabaseEx.DeletePendingLODFolder(jobFolderName);
                AssetDatabase.DeleteAsset(lodAssetDir);
                AssetDatabase.DeleteAsset(materialPath);

                UnityObject.DestroyImmediate(renderer.gameObject);
            });
        }