{"id":15035785,"url":"https://github.com/simplestargame/runtimemeshsimplification","last_synced_at":"2025-08-14T21:09:00.721Z","repository":{"id":188719149,"uuid":"679295706","full_name":"simplestargame/RuntimeMeshSimplification","owner":"simplestargame","description":"Unity Runtime Mesh Simplification","archived":false,"fork":false,"pushed_at":"2024-04-17T11:15:46.000Z","size":2022,"stargazers_count":128,"open_issues_count":1,"forks_count":11,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-09T23:15:06.326Z","etag":null,"topics":["csharp-code","mesh","simplify3d","unity3d"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simplestargame.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-08-16T14:20:12.000Z","updated_at":"2025-03-15T17:09:00.000Z","dependencies_parsed_at":"2024-04-17T12:34:50.421Z","dependency_job_id":"03ad052c-1835-418d-90bc-883b93387854","html_url":"https://github.com/simplestargame/RuntimeMeshSimplification","commit_stats":null,"previous_names":["simplestargame/simplemeshapisample","simplestargame/runtimemeshsimplification"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplestargame%2FRuntimeMeshSimplification","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplestargame%2FRuntimeMeshSimplification/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplestargame%2FRuntimeMeshSimplification/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simplestargame%2FRuntimeMeshSimplification/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simplestargame","download_url":"https://codeload.github.com/simplestargame/RuntimeMeshSimplification/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248125591,"owners_count":21051770,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp-code","mesh","simplify3d","unity3d"],"created_at":"2024-09-24T20:29:28.494Z","updated_at":"2025-04-09T23:15:13.403Z","avatar_url":"https://github.com/simplestargame.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Runtime Mesh Simplification\n\nWelcome to the Runtime Mesh Simplification Repository!  \nThis project provides a collection of script samples that simplify meshes in real-time using multi-threading, enabling efficient   rendering and performance improvements in applications with complex geometries, without sacrificing rendering frame rates.  \n\n![サンプルシーン](main.png)\n\n## Features\n- **Runtime Simplification:** Simplify meshes at runtime.  \n- **Preservation of Details:** The algorithm intelligently preserves important details to achieve the specified quality, ensuring high-quality visual output.  \n- **Optimization:** Significantly reduce the number of vertices and triangles, leading to faster rendering times and smoother user experiences.  \n- **Easy Integration:** Integration into existing projects is seamless – just pass an array of MeshFilters to a coroutine.  \n- **Threading:** Processing is offloaded to separate threads wherever possible to maintain rendering frame rates.  \n\n## Getting Started\nFollow these steps to integrate Runtime Mesh Simplification into your project:\n\n1. Clone this repository.\n1. Open the project from the cloned folder using Unity Hub.\n1. Open the sample scene to understand the process of mesh simplification.\n\n# ランタイム メッシュ簡素化\n\n**ランタイム メッシュ簡素化** リポジトリへようこそ！  \nこのプロジェクトは、複雑なジオメトリを含むアプリケーションでの効率的なレンダリングとパフォーマンス向上を可能にするため  \n描画フレームレートを落とさないよう、マルチスレッド処理にてメッシュをリアルタイムで簡素化するスクリプトサンプル群です。\n\n## 特徴\n\n- **ランタイム簡素化:** 実行時にメッシュをランタイムで簡素化します。\n- **細部の保持:** 指定した品質を目指してアルゴリズムは重要なディテールを賢く保持し、高品質の視覚出力を確保します。\n- **最適化:** 頂点と三角形の数を著しく減少させ、レンダリング時間の短縮とスムーズなユーザーエクスペリエンスを実現します。\n- **簡単な統合:** コルーチンにMeshFilterの配列を渡すだけなので、既存のプロジェクトに簡素化プロセスをシームレスに統合します。\n- **別スレッド化:** 描画フレームレートを落とさないようにするために、可能な限り処理が別スレッドで実行されます。\n\n## 始め方\n\n以下の手順に従って、ランタイム メッシュ簡素化をプロジェクトに統合します：\n\n1. このリポジトリをクローンします。\n1. Unity Hub 経由でクローンしたフォルダからプロジェクトを開きます。\n1. サンプルシーンを開いて、メッシュの簡素化処理を理解します。\n\n## How to use\n\n```csharp\nusing System.Collections;\nusing System.Linq;\nusing Unity.Collections;\nusing Unity.Jobs;\nusing UnityEngine;\nusing System.Threading.Tasks;\nusing UnityMeshSimplifier;\nusing Unity.Jobs.LowLevel.Unsafe;\n\nnamespace SimplestarGame\n{\n    public class SimpleMeshAPISample : MonoBehaviour\n    {\n        [SerializeField] Transform referenceTarget;\n        [SerializeField] Vector3 offsetPosition;\n        [SerializeField, Range(0, 1)] float quality = 1f;\n        [SerializeField] bool recalculateNormals = true;\n\n        float startTime;\n        float duration = 0.016f;\n\n        MeshSimplifier SimplifyMesh(MeshSimplifier meshSimplifier, Mesh.MeshData meshData)\n        {\n            meshSimplifier.SetMeshData(meshData);\n            meshSimplifier.SimplifyMesh(this.quality);\n            return meshSimplifier;\n        }\n\n        void MakeCustomLayoutMeshJob(Mesh.MeshDataArray meshDataArray, CustomLayoutMesh customLayoutMesh, MeshSimplifier simplifier, int meshIdx)\n        {\n            int subMeshCount = simplifier.SubMeshCount;\n            int[][] subMeshTrianglesArray = new int[subMeshCount][];\n            for (int subIdx = 0; subIdx \u003c subMeshCount; subIdx++)\n            {\n                subMeshTrianglesArray[subIdx] = simplifier.GetSubMeshTriangles(subIdx);\n            }\n            customLayoutMesh.SetMeshData(meshDataArray, meshIdx, subMeshCount, subMeshTrianglesArray,\n                simplifier.Vertices, simplifier.Normals, simplifier.Tangents, simplifier.Colors, simplifier.UV1);\n        }\n\n        static int GetNearestPowerOfTwo(int value)\n        {\n            int powerOfTwo = 1;\n\n            while (powerOfTwo \u003c value)\n            {\n                powerOfTwo *= 2;\n            }\n\n            int lowerPowerOfTwo = powerOfTwo / 2;\n            int upperPowerOfTwo = powerOfTwo;\n\n            return (upperPowerOfTwo - value) \u003c (value - lowerPowerOfTwo) ? upperPowerOfTwo : lowerPowerOfTwo;\n        }\n\n        bool HasTimeElapsed()\n        {\n            float currentTime = Time.realtimeSinceStartup;\n            float elapsedTime = currentTime - this.startTime;\n\n            return elapsedTime \u003e= this.duration;\n        }\n\n        void RestStartTime()\n        {\n            this.startTime = Time.realtimeSinceStartup;\n        }\n\n        IEnumerator Start()\n        {\n            MeshFilter[] meshFilters = this.referenceTarget.GetComponentsInChildren\u003cMeshFilter\u003e(true);\n            if (this.HasTimeElapsed())\n            {\n                this.RestStartTime();\n                yield return null;\n            }\n            // Copy\n            Mesh[] sourceMeshes = meshFilters.Select(meshFilter =\u003e meshFilter.sharedMesh).ToArray();\n            var customLayoutMesh = new CustomLayoutMesh(sourceMeshes.Length);\n            for (int meshIdx = 0; meshIdx \u003c sourceMeshes.Length; ++meshIdx)\n            {\n                if (this.HasTimeElapsed())\n                {\n                    this.RestStartTime();\n                    yield return null;\n                }\n                var sourceMesh = sourceMeshes[meshIdx];\n                customLayoutMesh.SetMeshData(meshIdx, sourceMesh);\n            }\n            JobHandle combinedHandle = customLayoutMesh.Schedule();\n            if (!combinedHandle.IsCompleted)\n            {\n                yield return null;\n            }\n            combinedHandle.Complete();\n            Mesh.MeshData[] meshDataArray = new Mesh.MeshData[sourceMeshes.Length];\n            for (int meshIdx = 0; meshIdx \u003c sourceMeshes.Length; meshIdx++)\n            {\n                if (this.HasTimeElapsed())\n                {\n                    this.RestStartTime();\n                    yield return null;\n                }\n                meshDataArray[meshIdx] = customLayoutMesh.GetMeshData(meshIdx);\n            }\n            // Simplify\n            Task\u003cMeshSimplifier\u003e[] simplifyTasks = new Task\u003cMeshSimplifier\u003e[sourceMeshes.Length];\n            for (int meshIdx = 0; meshIdx \u003c sourceMeshes.Length; meshIdx++)\n            {\n                if (this.HasTimeElapsed())\n                {\n                    this.RestStartTime();\n                    yield return null;\n                }\n                var meshSimplifier = new MeshSimplifier();\n                var meshData = meshDataArray[meshIdx];\n                simplifyTasks[meshIdx] = Task.Run(() =\u003e SimplifyMesh(meshSimplifier, meshData));\n            }\n            customLayoutMesh.Dispose();\n            int lastCompletedTaskIndex = 0;\n            while (lastCompletedTaskIndex \u003c simplifyTasks.Length)\n            {\n                if (!simplifyTasks[lastCompletedTaskIndex].IsCompleted)\n                {\n                    yield return null;\n                }\n                else\n                {\n                    lastCompletedTaskIndex++;\n                }\n            }\n            customLayoutMesh.Allocate(simplifyTasks.Length);\n            Task[] createJobTasks = new Task[simplifyTasks.Length];\n            for (int meshIdx = 0; meshIdx \u003c simplifyTasks.Length; ++meshIdx)\n            {\n                if (this.HasTimeElapsed())\n                {\n                    this.RestStartTime();\n                    yield return null;\n                }\n                var newMeshDataArray = Mesh.AllocateWritableMeshData(1);\n                var meshSimplifier = simplifyTasks[meshIdx].Result;\n                var newMeshIndex = meshIdx;\n                createJobTasks[meshIdx] = Task.Run(() =\u003e MakeCustomLayoutMeshJob(newMeshDataArray, customLayoutMesh, meshSimplifier, newMeshIndex));\n            }\n            lastCompletedTaskIndex = 0;\n            while (lastCompletedTaskIndex \u003c createJobTasks.Length)\n            {\n                if (!createJobTasks[lastCompletedTaskIndex].IsCompleted)\n                {\n                    yield return null;\n                }\n                else\n                {\n                    lastCompletedTaskIndex++;\n                }\n            }\n            combinedHandle = customLayoutMesh.Schedule();\n            if (!combinedHandle.IsCompleted)\n            {\n                yield return null;\n            }\n            combinedHandle.Complete();\n            var newMeshes = new Mesh[simplifyTasks.Length];\n            for (int meshIdx = 0; meshIdx \u003c sourceMeshes.Length; meshIdx++)\n            {\n                if (this.HasTimeElapsed())\n                {\n                    this.RestStartTime();\n                    yield return null;\n                }\n                newMeshes[meshIdx] = customLayoutMesh.ToMesh(meshIdx);\n            }\n            customLayoutMesh.Dispose();\n            // Bake\n            NativeArray\u003cint\u003e meshIds = new NativeArray\u003cint\u003e(newMeshes.Length, Allocator.Persistent);\n            for (int meshIdx = 0; meshIdx \u003c newMeshes.Length; ++meshIdx)\n            {\n                meshIds[meshIdx] = newMeshes[meshIdx].GetInstanceID();\n            }\n            var bakeMeshJob = new BakeMeshJob(meshIds);\n            int innerloopBatchCount = GetNearestPowerOfTwo(meshIds.Length / JobsUtility.JobWorkerCount);\n            var bakeMeshJobHandle = bakeMeshJob.Schedule(meshIds.Length, innerloopBatchCount);\n            while (!bakeMeshJobHandle.IsCompleted)\n            {\n                yield return null;\n            }\n            bakeMeshJobHandle.Complete();\n            meshIds.Dispose();\n            for (int i = 0; i \u003c newMeshes.Length; i++)\n            {\n                if (this.HasTimeElapsed())\n                {\n                    this.RestStartTime();\n                    yield return null;\n                }\n                var newMesh = newMeshes[i];\n                var sourceMeshFilter = meshFilters[i];\n                GameObject newGameObject = new GameObject(\"ClonedMeshObject\");\n                newGameObject.transform.position = sourceMeshFilter.transform.position + this.offsetPosition;\n                newGameObject.transform.rotation = sourceMeshFilter.transform.rotation;\n                if (this.recalculateNormals)\n                {\n                    newMesh.RecalculateNormals();\n                    newMesh.RecalculateTangents();\n                }\n                newGameObject.AddComponent\u003cMeshFilter\u003e().sharedMesh = newMesh;\n                newGameObject.AddComponent\u003cMeshRenderer\u003e().sharedMaterials = sourceMeshFilter.GetComponent\u003cMeshRenderer\u003e().sharedMaterials;\n                newGameObject.AddComponent\u003cMeshCollider\u003e().sharedMesh = newMesh;\n            }\n        }\n    }\n}\n```\n\n## License\nThis project is licensed under the MIT License.\n\n## Contribution\nIf you find a bug, have an enhancement idea, or want to contribute in any other way, please open an issue or submit a pull request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimplestargame%2Fruntimemeshsimplification","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimplestargame%2Fruntimemeshsimplification","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimplestargame%2Fruntimemeshsimplification/lists"}