Пример #1
0
        private void SetDecimation(float value, Dictionary <string, float> variables)
        {
            ConnectedMesh[] connectedMeshes = _originalMeshes.Select(x => UnityConverter.ToSharedMesh(x).ToConnectedMesh()).ToArray();

            foreach (ConnectedMesh connectedMesh in connectedMeshes)
            {
                for (int i = 0; i < connectedMesh.attributeDefinitions.Length; i++)
                {
                    switch (connectedMesh.attributeDefinitions[i].type)
                    {
                    case AttributeType.Normals:
                        connectedMesh.attributeDefinitions[i].weight = variables["NormalWeight"];
                        break;

                    case AttributeType.UVs:
                        connectedMesh.attributeDefinitions[i].weight = variables["UVsWeight"];
                        break;
                    }
                }
            }

            foreach (ConnectedMesh connectedMesh in connectedMeshes)
            {
                // Important step :
                // We merge positions to increase chances of having correct topology information
                // We merge attributes in order to make interpolation properly operate on every face
                connectedMesh.MergePositions(0.0001f /*variables["MergeThreshold"]*/);
                connectedMesh.MergeAttributes();
                connectedMesh.Compact();
            }

            DecimateModifier.MergeNormalsThresholdDegrees = variables["MergeNormalsThreshold"];
            //DecimateModifier.UpdateFarNeighbors = variables["UpdateFarNeighbors"] > 0.5;
            //DecimateModifier.UpdateMinsOnCollapse = variables["UpdateMinsOnCollapse"] > 0.5;
            //DecimateModifier.UseEdgeLength = variables["UseEdgeLength"] > 0.5;
            DecimateModifier.CollapseToMidpointPenalty = variables["CollapseToMidpointPenalty"];
            ConnectedMesh.EdgeBorderPenalty            = variables["EdgeBorderPenalty"];

            SceneDecimator sceneDecimator = new SceneDecimator();

            sceneDecimator.Initialize(connectedMeshes);

            sceneDecimator.DecimateToRatio(value);

            for (int i = 0; i < connectedMeshes.Length; i++)
            {
                _meshes[i].Clear();
                connectedMeshes[i].ToSharedMesh().ToUnityMesh(_meshes[i]);
                _meshes[i].bindposes = _originalMeshes[i].bindposes;
            }
        }
Пример #2
0
    private void OnValueChanged(float value)
    {
        polycountLabel.text = $"{Math.Round(100 * value)}% ({Math.Round(value * _polycount)}/{_polycount} triangles)";

        Profiling.Start("Convert");

        var connectedMeshes = _originalMeshes.Select(x => UnityConverter.ToSharedMesh(x).ToConnectedMesh()).ToArray();

        Debug.Log(Profiling.End("Convert"));
        Profiling.Start("Clean");

        foreach (var connectedMesh in connectedMeshes)
        {
            // Important step :
            // We merge positions to increase chances of having correct topology information
            // We merge attributes in order to make interpolation properly operate on every face
            connectedMesh.MergePositions(0.0001f);
            connectedMesh.MergeAttributes();
            connectedMesh.Compact();
        }

        Debug.Log(Profiling.End("Clean"));
        Profiling.Start("Decimate");

        SceneDecimator sceneDecimator = new SceneDecimator();

        sceneDecimator.Initialize(connectedMeshes);

        sceneDecimator.DecimateToRatio(value);

        Debug.Log(Profiling.End("Decimate"));
        Profiling.Start("Convert back");

        for (int i = 0; i < connectedMeshes.Length; i++)
        {
            _meshes[i].Clear();
            connectedMeshes[i].ToSharedMesh().ToUnityMesh(_meshes[i]);
            _meshes[i].bindposes = _originalMeshes[i].bindposes;
        }

        Debug.Log(Profiling.End("Convert back"));
    }
Пример #3
0
        public static void GenerateLODs(LODGroup lodGroup, HashSet <Mesh> newMeshes = null)
        {
            LOD[] lods = lodGroup.GetLODs();

            // Cleanup
            for (int i = 1; i < lods.Length; i++)
            {
                foreach (Renderer renderer in lods[i].renderers)
                {
                    if (renderer != null)
                    {
                        Object.DestroyImmediate(renderer.gameObject);
                    }
                }
            }

            if (newMeshes == null)
            {
                newMeshes = new HashSet <Mesh>();
            }

            // Assign LOD0
            Renderer[] renderers = lodGroup.GetComponentsInChildren <Renderer>();
            lods[0].renderers = renderers;

            Dictionary <Mesh, ConnectedMesh> uniqueMeshes = new Dictionary <Mesh, ConnectedMesh>();

            foreach (Renderer renderer in renderers)
            {
                if (renderer is MeshRenderer meshRenderer)
                {
                    MeshFilter meshFilter = renderer.gameObject.GetComponent <MeshFilter>();
                    if (meshFilter)
                    {
                        Mesh mesh = meshFilter.sharedMesh;
                        if (!uniqueMeshes.ContainsKey(mesh))
                        {
                            uniqueMeshes.TryAdd(mesh, m => UnityConverter.ToSharedMesh(m).ToConnectedMesh());
                        }
                    }
                }
                else if (renderer is SkinnedMeshRenderer skinnedMeshRenderer)
                {
                    Mesh mesh = skinnedMeshRenderer.sharedMesh;
                    if (!uniqueMeshes.ContainsKey(mesh))
                    {
                        uniqueMeshes.TryAdd(mesh, m => UnityConverter.ToSharedMesh(m).ToConnectedMesh());
                    }
                }
            }

            foreach (KeyValuePair <Mesh, ConnectedMesh> uniqueMesh in uniqueMeshes)
            {
                uniqueMesh.Value.MergePositions(0.0001);
                uniqueMesh.Value.MergeAttributes();
                uniqueMesh.Value.Compact();
            }

            SceneDecimator sceneDecimator = new SceneDecimator();

            sceneDecimator.Initialize(uniqueMeshes.Values);

            // Build LODs
            for (int i = 1; i < lods.Length; i++)
            {
                // Decimates gradually
                sceneDecimator.DecimateToRatio(lods[i - 1].screenRelativeTransitionHeight);

                Dictionary <Mesh, Mesh> optimizedMeshes = uniqueMeshes.ToDictionary(x => x.Key, x => x.Value.ToSharedMesh().ToUnityMesh());

                List <Renderer> lodRenderers = new List <Renderer>();

                foreach (Renderer renderer in renderers)
                {
                    if (renderer is MeshRenderer meshRenderer)
                    {
                        MeshFilter meshFilter = renderer.gameObject.GetComponent <MeshFilter>();
                        if (meshFilter)
                        {
                            GameObject gameObject = new GameObject(renderer.gameObject.name + "_LOD" + i);
                            gameObject.transform.parent        = renderer.transform;
                            gameObject.transform.localPosition = UnityEngine.Vector3.zero;
                            gameObject.transform.localRotation = UnityEngine.Quaternion.identity;
                            gameObject.transform.localScale    = UnityEngine.Vector3.one;

                            MeshRenderer mr = gameObject.AddComponent <MeshRenderer>();
                            MeshFilter   mf = gameObject.AddComponent <MeshFilter>();

                            Mesh originalMesh  = meshFilter.sharedMesh;
                            Mesh optimizedMesh = optimizedMeshes[originalMesh]; // Todo : Don't create new mesh if it's the same (tri count);

                            optimizedMesh.name = originalMesh.name + "_LOD" + i;

                            mr.sharedMaterials = meshRenderer.sharedMaterials;
                            mf.sharedMesh      = optimizedMesh;

                            newMeshes.Add(optimizedMesh);

                            lodRenderers.Add(mr);
                        }
                    }
                    else if (renderer is SkinnedMeshRenderer skinnedMeshRenderer)
                    {
                        GameObject gameObject = new GameObject(renderer.gameObject.name + "_LOD" + i);
                        gameObject.transform.parent        = renderer.transform;
                        gameObject.transform.localPosition = UnityEngine.Vector3.zero;
                        gameObject.transform.localRotation = UnityEngine.Quaternion.identity;
                        gameObject.transform.localScale    = UnityEngine.Vector3.one;

                        SkinnedMeshRenderer smr = gameObject.AddComponent <SkinnedMeshRenderer>();
                        smr.bones    = skinnedMeshRenderer.bones;
                        smr.rootBone = skinnedMeshRenderer.rootBone;

                        Mesh originalMesh  = skinnedMeshRenderer.sharedMesh;
                        Mesh optimizedMesh = optimizedMeshes[originalMesh]; // Todo : Don't create new mesh if it's the same (tri count);

                        optimizedMesh.name = originalMesh.name + "_LOD" + i;

                        smr.sharedMaterials = skinnedMeshRenderer.sharedMaterials;
                        smr.sharedMesh      = optimizedMesh;

                        optimizedMesh.bindposes = originalMesh.bindposes; // Copy poses

                        newMeshes.Add(optimizedMesh);

                        lodRenderers.Add(smr);
                    }
                }

                ///Debug.Log($"LOD{i} created with {lodRenderers.Count} renderers at {100f * lods[i - 1].screenRelativeTransitionHeight}% poly ratio");
                lods[i].renderers = lodRenderers.ToArray();
            }

            lodGroup.SetLODs(lods);
        }