예제 #1
0
 void EditorUpdate()
 {
     if ((m_CoroutineQueue.Count > 0 || m_SceneDirty || (m_RootVolume && m_RootVolume.dirty)) && m_ServiceCoroutineQueue == null)
     {
         m_ServiceCoroutineQueue = MonoBehaviourHelper.StartCoroutine(ServiceCoroutineQueue());
     }
 }
예제 #2
0
        public JobHandle Generate(NativeArray <JobHandle>?jobDependencies = null)
        {
            // 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 = new GenerateMeshLODJob();

            job.inputMesh = inputMesh.ToWorkingMesh(Allocator.TempJob);
            job.quality   = quality;
            var typeNameBytes = Encoding.UTF8.GetBytes(meshSimplifierType.AssemblyQualifiedName);

            job.meshSimplifierTypeName = new NativeArray <byte>(typeNameBytes, Allocator.TempJob);
            job.outputMesh             = new WorkingMesh(Allocator.Persistent, inputMesh.vertexCount, inputMesh.GetTriangleCount(),
                                                         inputMesh.subMeshCount, inputMesh.blendShapeCount);

            JobHandle jobHandle;

            if (jobDependencies.HasValue)
            {
                jobHandle = job.Schedule(JobHandle.CombineDependencies(jobDependencies.Value));
            }
            else
            {
                jobHandle = job.Schedule();
            }

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

            return(jobHandle);
        }
예제 #3
0
        public JobHandle Generate(NativeArray <JobHandle>?jobDependencies = null)
        {
            // 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;
            job.OutputMesh = new WorkingMesh(Allocator.Persistent, inputMesh.vertexCount, inputMesh.GetTriangleCount(),
                                             inputMesh.subMeshCount, inputMesh.blendShapeCount);

            JobHandle jobHandle;

            if (jobDependencies.HasValue)
            {
                jobHandle = job.Schedule(JobHandle.CombineDependencies(jobDependencies.Value));
            }
            else
            {
                jobHandle = job.Schedule();
            }

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

            return(jobHandle);
        }
예제 #4
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);
            });
        }
예제 #5
0
        public void Destroy()
        {
            MonoBehaviourHelper.StartCoroutine(ObjectUtils.FindGameObject("HLODs",
                                                                          root => { DestroyImmediate(root); }));

            Utilities.FileUtils.DeleteDirectory(Application.dataPath + Path.DirectorySeparatorChar + SceneLOD.GetSceneLODPath());
            AssetDatabase.Refresh();
        }
예제 #6
0
        void EditorUpdate()
        {
            if (m_Updater == null)
            {
                MonoBehaviourHelper.StartCoroutine(SetLODUpdater());
            }

            if (SceneLODCreator.instance.IsCreating() == true)
            {
                s_HLODEnabled = false;
            }
        }
예제 #7
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();
        }
예제 #8
0
        static void UpdateDependencies()
        {
#if HAS_MINIMUM_REQUIRED_VERSION
            if (meshSimplifierType == null)
            {
                MonoBehaviourHelper.StartCoroutine(GetDefaultSimplifier());
                ModelImporterLODGenerator.enabled = false;
                return;
            }

            MonoBehaviourHelper.maxSharedExecutionTimeMS = maxExecutionTime == 0 ? Mathf.Infinity : maxExecutionTime;

            LODDataEditor.meshSimplifier         = meshSimplifierType.AssemblyQualifiedName;
            LODDataEditor.batcher                = batcherType.AssemblyQualifiedName;
            LODDataEditor.maxLODGenerated        = maxLOD;
            LODDataEditor.initialLODMaxPolyCount = initialLODMaxPolyCount;

            LODVolume.meshSimplifierType = meshSimplifierType;
            LODVolume.batcherType        = batcherType;
            LODVolume.drawBounds         = sceneLODEnabled && showVolumeBounds;

            ModelImporterLODGenerator.saveAssets             = saveAssets;
            ModelImporterLODGenerator.meshSimplifierType     = meshSimplifierType;
            ModelImporterLODGenerator.maxLOD                 = maxLOD;
            ModelImporterLODGenerator.enabled                = generateOnImport;
            ModelImporterLODGenerator.initialLODMaxPolyCount = initialLODMaxPolyCount;

            if (sceneLODEnabled && !SceneLOD.activated)
            {
                if (!SceneLOD.instance)
                {
                    Debug.LogError("SceneLOD failed to start");
                }
            }
            else if (!sceneLODEnabled && SceneLOD.activated)
            {
                UnityObject.DestroyImmediate(SceneLOD.instance);
            }
#else
            ModelImporterLODGenerator.enabled = false;
#endif
        }
예제 #9
0
        IEnumerator ServiceCoroutineQueue()
        {
            m_ServiceCoroutineExecutionTime.Start();

            if (m_SceneDirty)
            {
                m_CoroutineQueue.Enqueue(UpdateOctree());
                m_SceneDirty = false;
            }

            if (m_RootVolume && m_RootVolume.dirty)
            {
                m_CoroutineQueue.Enqueue(m_RootVolume.UpdateHLODs());
            }

            while (m_CoroutineQueue.Count > 0)
            {
                yield return(MonoBehaviourHelper.StartCoroutine(m_CoroutineQueue.Dequeue()));
            }

            ResetServiceCoroutineQueue();
        }
예제 #10
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);
        }
예제 #11
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);
            });
        }
예제 #12
0
        static void GenerateLODs(GameObject go)
        {
            // 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 meshFilters = go.GetComponentsInChildren <MeshFilter>();

            if (meshFilters.Length > 0)
            {
                var lodGroup = go.GetComponent <LODGroup>();
                if (!lodGroup)
                {
                    lodGroup = go.AddComponent <LODGroup>();
                }

                var lods = new LOD[maxLOD + 1];
                var lod0 = lods[0];
                lod0.renderers = go.GetComponentsInChildren <MeshRenderer>();
                lod0.screenRelativeTransitionHeight = 0.5f;
                lods[0] = lod0;

                var meshes = new List <Mesh>();

                for (int l = 1; l <= maxLOD; l++)
                {
                    var lodRenderers = new List <MeshRenderer>();
                    foreach (var mf in meshFilters)
                    {
                        var sharedMesh = mf.sharedMesh;

                        if (!sharedMesh)
                        {
                            Debug.LogWarning("AutoLOD: Missing mesh " + mf.name, mf);
                            continue;
                        }

                        var lodTransform = EditorUtility.CreateGameObjectWithHideFlags(string.Format("{0} LOD{1}", sharedMesh.name, l),
                                                                                       k_DefaultHideFlags, typeof(MeshFilter), typeof(MeshRenderer)).transform;
                        lodTransform.SetParent(mf.transform, false);

                        var lodMF       = lodTransform.GetComponent <MeshFilter>();
                        var lodRenderer = lodTransform.GetComponent <MeshRenderer>();

                        lodRenderers.Add(lodRenderer);

                        EditorUtility.CopySerialized(mf, lodMF);
                        EditorUtility.CopySerialized(mf.GetComponent <MeshRenderer>(), lodRenderer);

                        var simplifiedMesh = new Mesh();
                        simplifiedMesh.name = sharedMesh.name + string.Format(" LOD{0}", l);
                        lodMF.sharedMesh    = simplifiedMesh;
                        meshes.Add(simplifiedMesh);

                        var meshLOD = MeshLOD.GetGenericInstance(meshSimplifierType);
                        meshLOD.InputMesh  = sharedMesh;
                        meshLOD.OutputMesh = simplifiedMesh;
                        meshLOD.Quality    = Mathf.Pow(0.5f, l);
                        meshLOD.Generate();
                    }

                    var lod = lods[l];
                    lod.renderers = lodRenderers.ToArray();
                    lod.screenRelativeTransitionHeight = l == maxLOD ? 0.01f : Mathf.Pow(0.5f, l + 1);
                    lods[l] = lod;
                }

                lodGroup.ForceLOD(0);
                lodGroup.SetLODs(lods.ToArray());
                lodGroup.RecalculateBounds();
                lodGroup.ForceLOD(-1);

#if UNITY_2018_2_OR_NEWER
                var prefab = PrefabUtility.GetCorrespondingObjectFromSource(go);
#else
                var prefab = PrefabUtility.GetPrefabParent(go);
#endif
                if (prefab)
                {
                    var lodsAssetPath = GetLODAssetPath(prefab);
                    if (File.Exists(lodsAssetPath))
                    {
                        meshes.ForEach(m => AssetDatabase.AddObjectToAsset(m, lodsAssetPath));
                    }
                    else
                    {
                        ObjectUtils.CreateAssetFromObjects(meshes.ToArray(), lodsAssetPath);
                    }
                }
            }
        }
예제 #13
0
 static void GenerateLODs(MenuCommand menuCommand)
 {
     MonoBehaviourHelper.StartCoroutine(GenerateLODsCoroutine(menuCommand));
 }
예제 #14
0
        void OnPostprocessModel(GameObject go)
        {
            if (!go.GetComponentInChildren <LODGroup>() && meshSimplifierType != null && IsEditable(assetPath))
            {
                if (go.GetComponentsInChildren <SkinnedMeshRenderer>().Any())
                {
                    Debug.LogWarning("Automatic LOD generation on skinned meshes is not currently supported");
                    return;
                }

                var  originalMeshFilters = go.GetComponentsInChildren <MeshFilter>();
                uint polyCount           = 0;
                foreach (var mf in originalMeshFilters)
                {
                    var m = mf.sharedMesh;
                    for (int i = 0; i < m.subMeshCount; i++)
                    {
                        var topology   = m.GetTopology(i);
                        var indexCount = m.GetIndexCount(i);

                        switch (topology)
                        {
                        case MeshTopology.Quads:
                            indexCount /= 4;
                            break;

                        case MeshTopology.Triangles:
                            indexCount /= 3;
                            break;

                        case MeshTopology.Lines:
                        case MeshTopology.LineStrip:
                            indexCount /= 2;
                            break;
                        }

                        polyCount += indexCount;
                    }
                }

                var meshLODs         = new List <IMeshLOD>();
                var preprocessMeshes = new HashSet <int>();

                var lodData          = GetLODData(assetPath);
                var overrideDefaults = lodData.overrideDefaults;
                var importSettings   = lodData.importSettings;

                // It's possible to override defaults to either generate on import or to not generate and use specified
                // LODs in the override, but in the case where we are not overriding and globally we are not generating
                // on import, then there should be no further processing.
                if (!overrideDefaults && !enabled)
                {
                    return;
                }

                if (importSettings.generateOnImport)
                {
                    if (importSettings.maxLODGenerated == 0 && polyCount <= importSettings.initialLODMaxPolyCount)
                    {
                        return;
                    }

                    var simplifierType = Type.GetType(importSettings.meshSimplifier) ?? meshSimplifierType;

                    if (polyCount > importSettings.initialLODMaxPolyCount)
                    {
                        foreach (var mf in originalMeshFilters)
                        {
                            var inputMesh = mf.sharedMesh;

                            var outputMesh = new Mesh();
                            outputMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                            outputMesh.name        = inputMesh.name;
                            outputMesh.bounds      = inputMesh.bounds;
                            mf.sharedMesh          = outputMesh;

                            var meshLOD = MeshLOD.GetGenericInstance(meshSimplifierType);
                            meshLOD.InputMesh  = inputMesh;
                            meshLOD.OutputMesh = outputMesh;
                            meshLOD.Quality    = (float)importSettings.initialLODMaxPolyCount / (float)polyCount;
                            meshLODs.Add(meshLOD);

                            preprocessMeshes.Add(outputMesh.GetInstanceID());
                        }
                    }

                    // Clear out previous LOD data in case the number of LODs has been reduced
                    for (int i = 0; i <= LODData.MaxLOD; i++)
                    {
                        lodData[i] = null;
                    }

                    lodData[0] = originalMeshFilters.Select(mf => mf.GetComponent <Renderer>()).ToArray();

                    for (int i = 1; i <= importSettings.maxLODGenerated; i++)
                    {
                        var lodMeshes = new List <Renderer>();

                        foreach (var mf in originalMeshFilters)
                        {
                            var inputMesh = mf.sharedMesh;

                            var lodTransform = EditorUtility.CreateGameObjectWithHideFlags(mf.name,
                                                                                           k_DefaultHideFlags, typeof(MeshFilter), typeof(MeshRenderer)).transform;
                            lodTransform.parent        = mf.transform;
                            lodTransform.localPosition = Vector3.zero;
                            lodTransform.localRotation = Quaternion.identity;
                            lodTransform.localScale    = new Vector3(1, 1, 1);

                            var lodMF       = lodTransform.GetComponent <MeshFilter>();
                            var lodRenderer = lodTransform.GetComponent <MeshRenderer>();

                            AppendLODNameToRenderer(lodRenderer, i);

                            var outputMesh = new Mesh();
                            outputMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
                            outputMesh.name        = string.Format("{0} LOD{1}", inputMesh.name, i);
                            outputMesh.bounds      = inputMesh.bounds;
                            lodMF.sharedMesh       = outputMesh;

                            lodMeshes.Add(lodRenderer);

                            EditorUtility.CopySerialized(mf.GetComponent <MeshRenderer>(), lodRenderer);

                            var meshLOD = MeshLOD.GetGenericInstance(meshSimplifierType);
                            meshLOD.InputMesh  = inputMesh;
                            meshLOD.OutputMesh = outputMesh;
                            meshLOD.Quality    = Mathf.Pow(0.5f, i);
                            meshLODs.Add(meshLOD);
                        }

                        lodData[i] = lodMeshes.ToArray();
                    }

                    // Change the name of the original renderers last, so the name change doesn't end up in the clones for other LODs
                    AppendLODNameToRenderers(go.transform, 0);

                    if (meshLODs.Count > 0)
                    {
                        if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(lodData)))
                        {
                            AssetDatabase.CreateAsset(lodData, GetLODDataPath(assetPath));
                        }
                        else
                        {
                            var objects = AssetDatabase.LoadAllAssetsAtPath(GetLODDataPath(assetPath));
                            foreach (var o in objects)
                            {
                                var mesh = o as Mesh;
                                if (mesh)
                                {
                                    UnityObject.DestroyImmediate(mesh, true);
                                }
                            }
                            EditorUtility.SetDirty(lodData);
                        }
                        meshLODs.ForEach(ml => AssetDatabase.AddObjectToAsset(ml.OutputMesh, lodData));
                        if (saveAssets)
                        {
                            AssetDatabase.SaveAssets();
                        }

                        if (preprocessMeshes.Count > 0)
                        {
                            // Process dependencies first
                            var jobDependencies = new List <JobHandle>();
                            meshLODs.RemoveAll(ml =>
                            {
                                if (preprocessMeshes.Contains(ml.OutputMesh.GetInstanceID()))
                                {
                                    jobDependencies.Add(ml.Generate());
                                    return(true);
                                }

                                return(false);
                            });

                            // Process remaining meshes
                            foreach (var ml in meshLODs)
                            {
                                MonoBehaviourHelper.StartCoroutine(ml.GenerateAfterDependencies(jobDependencies));
                            }
                        }
                        else
                        {
                            foreach (var ml in meshLODs)
                            {
                                ml.Generate();
                            }
                        }
                    }
                }
                else
                {
                    // Don't allow overriding LOD0
                    lodData[0] = originalMeshFilters.Select(mf =>
                    {
                        var r = mf.GetComponent <Renderer>();
                        AppendLODNameToRenderer(r, 0);
                        return(r);
                    }).ToArray();

                    for (int i = 1; i <= LODData.MaxLOD; i++)
                    {
                        var renderers = lodData[i];
                        for (int j = 0; j < renderers.Length; j++)
                        {
                            var r = renderers[j];

                            var lodTransform = EditorUtility.CreateGameObjectWithHideFlags(r.name,
                                                                                           k_DefaultHideFlags, typeof(MeshFilter), typeof(MeshRenderer)).transform;
                            lodTransform.parent        = go.transform;
                            lodTransform.localPosition = Vector3.zero;

                            var lodMF       = lodTransform.GetComponent <MeshFilter>();
                            var lodRenderer = lodTransform.GetComponent <MeshRenderer>();

                            EditorUtility.CopySerialized(r.GetComponent <MeshFilter>(), lodMF);
                            EditorUtility.CopySerialized(r, lodRenderer);

                            AppendLODNameToRenderer(lodRenderer, i);

                            renderers[j] = lodRenderer;
                        }
                    }
                }

                List <LOD> lods        = new List <LOD>();
                var        maxLODFound = -1;
                for (int i = 0; i <= LODData.MaxLOD; i++)
                {
                    var renderers = lodData[i];
                    if (renderers == null || renderers.Length == 0)
                    {
                        break;
                    }

                    maxLODFound++;
                }

                var importerRef       = new SerializedObject(assetImporter);
                var importerLODLevels = importerRef.FindProperty("m_LODScreenPercentages");
                for (int i = 0; i <= maxLODFound; i++)
                {
                    var lod = new LOD();
                    lod.renderers = lodData[i];
                    var screenPercentage = i == maxLODFound ? 0.01f : Mathf.Pow(0.5f, i + 1);

                    // Use the model importer percentages if they exist
                    if (i < importerLODLevels.arraySize && maxLODFound == importerLODLevels.arraySize)
                    {
                        var element = importerLODLevels.GetArrayElementAtIndex(i);
                        screenPercentage = element.floatValue;
                    }

                    lod.screenRelativeTransitionHeight = screenPercentage;
                    lods.Add(lod);
                }

                if (importerLODLevels.arraySize != 0 && maxLODFound != importerLODLevels.arraySize - 1)
                {
                    Debug.LogWarning("The model has an existing lod group, but it's settings will not be used because " +
                                     "the specified lod count in the AutoLOD settings is different.");
                }

                var lodGroup = go.AddComponent <LODGroup>();
                lodGroup.SetLODs(lods.ToArray());
                lodGroup.RecalculateBounds();

                // Keep model importer in sync
                importerLODLevels.ClearArray();
                for (int i = 0; i < lods.Count; i++)
                {
                    var lod = lods[i];
                    importerLODLevels.InsertArrayElementAtIndex(i);
                    var element = importerLODLevels.GetArrayElementAtIndex(i);
                    element.floatValue = lod.screenRelativeTransitionHeight;
                }
                importerRef.ApplyModifiedPropertiesWithoutUndo();

                s_ModelAssetsProcessed.Add(assetPath);
            }
        }
예제 #15
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);
            });
        }