From 1b85a4983661ea5df1414cc70065374e91eb7f5e Mon Sep 17 00:00:00 2001 From: chorome Date: Wed, 1 Jul 2020 12:36:44 +0900 Subject: [PATCH 1/2] ContinueWithCoroutine method supports a return value and a argument --- Assets/VRM/DepthFirstScheduler/Functor.cs | 30 ++++++++++++------- Assets/VRM/DepthFirstScheduler/Schedulable.cs | 23 ++++++++++---- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/Assets/VRM/DepthFirstScheduler/Functor.cs b/Assets/VRM/DepthFirstScheduler/Functor.cs index 3f7f6a595..735dbbdf2 100644 --- a/Assets/VRM/DepthFirstScheduler/Functor.cs +++ b/Assets/VRM/DepthFirstScheduler/Functor.cs @@ -75,10 +75,18 @@ namespace DepthFirstScheduler #region CoroutineFunctor public class CoroutineFunctor : IFunctor { - T m_result; public T GetResult() { - return m_result; + if (m_last?.Current == null) return default; + + try + { + return (T)m_last.Current; + } + catch + { + return default; + } } Exception m_error; @@ -87,12 +95,11 @@ namespace DepthFirstScheduler return m_error; } - Func m_arg; - Func m_starter; + Func m_starter; Stack m_it; - public CoroutineFunctor(Func arg, Func starter) + private IEnumerator m_last; + public CoroutineFunctor(Func starter) { - m_arg = arg; m_starter = starter; } @@ -100,9 +107,8 @@ namespace DepthFirstScheduler { if (m_it == null) { - m_result = m_arg(); m_it = new Stack(); - m_it.Push(m_starter(m_result)); + m_it.Push(m_starter()); } try @@ -119,7 +125,7 @@ namespace DepthFirstScheduler } else { - m_it.Pop(); + m_last = m_it.Pop(); } return ExecutionStatus.Continue; } @@ -139,9 +145,11 @@ namespace DepthFirstScheduler public static class CoroutineFunctor { - public static CoroutineFunctor Create(Func arg, Func starter) + /// 引数の型 + /// 結果の型 + public static CoroutineFunctor Create(Func arg, Func starter) { - return new CoroutineFunctor(arg, starter); + return new CoroutineFunctor(() => starter(arg())); } } #endregion diff --git a/Assets/VRM/DepthFirstScheduler/Schedulable.cs b/Assets/VRM/DepthFirstScheduler/Schedulable.cs index 1969df591..3605c1b44 100644 --- a/Assets/VRM/DepthFirstScheduler/Schedulable.cs +++ b/Assets/VRM/DepthFirstScheduler/Schedulable.cs @@ -137,10 +137,10 @@ namespace DepthFirstScheduler return schedulable; } - public Schedulable AddCoroutine(IScheduler scheduler, Func starter) + public Schedulable AddCoroutine(IScheduler scheduler, Func starter) { - var func = CoroutineFunctor.Create(() => default(T), _ => starter()); - var schedulable = new Schedulable(scheduler, func); + var func = CoroutineFunctor.Create(() => default(Unit), _ => starter()); + var schedulable = new Schedulable(scheduler, func); AddChild(schedulable); return schedulable; } @@ -168,15 +168,26 @@ namespace DepthFirstScheduler return schedulable; } - public Schedulable ContinueWithCoroutine(IScheduler scheduler, Func starter) + public Schedulable ContinueWithCoroutine(IScheduler scheduler, Func starter) + { + return ContinueWithCoroutine(scheduler, _ => starter()); + } + + public Schedulable ContinueWithCoroutine(IScheduler scheduler, Func starter) { if (Parent == null) { throw new NoParentException(); } - var func = CoroutineFunctor.Create(() => default(T), _ => starter()); - var schedulable = new Schedulable(scheduler, func); + Func getResult = null; + if (Func != null) + { + getResult = Func.GetResult; + } + + var func = CoroutineFunctor.Create(getResult, starter); + var schedulable = new Schedulable(scheduler, func); Parent.AddChild(schedulable); return schedulable; } From c50ca1484cdeb75b2be3b18212bcc79d33a4540e Mon Sep 17 00:00:00 2001 From: chorome Date: Wed, 1 Jul 2020 14:24:33 +0900 Subject: [PATCH 2/2] load balance BuildMesh --- .../VRM/UniGLTF/Scripts/IO/ImporterContext.cs | 59 +++++--- Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs | 129 ++++++++++++++++++ 2 files changed, 166 insertions(+), 22 deletions(-) diff --git a/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs b/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs index d659a1fa9..e1cc1ad69 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/ImporterContext.cs @@ -372,6 +372,9 @@ namespace UniGLTF #endregion #region Load. Build unity objects + + public bool EnableLoadBalancing; + /// /// ReadAllBytes, Parse, Create GameObject /// @@ -560,28 +563,7 @@ namespace UniGLTF return meshImporter.ReadMesh(this, index); } }) - .ContinueWith(Scheduler.MainThread, x => - { - using (MeasureTime("BuildMesh")) - { - var meshWithMaterials = MeshImporter.BuildMesh(this, x); - - var mesh = meshWithMaterials.Mesh; - - // mesh name - if (string.IsNullOrEmpty(mesh.name)) - { - mesh.name = string.Format("UniGLTF import#{0}", i); - } - var originalName = mesh.name; - for (int j = 1; Meshes.Any(y => y.Mesh.name == mesh.name); ++j) - { - mesh.name = string.Format("{0}({1})", originalName, j); - } - - return meshWithMaterials; - } - }) + .ContinueWithCoroutine(Scheduler.MainThread, x => BuildMesh(x, index)) .ContinueWith(Scheduler.ThreadPool, x => Meshes.Add(x)) ; } @@ -654,6 +636,39 @@ namespace UniGLTF } yield return null; } + + IEnumerator BuildMesh(MeshImporter.MeshContext x, int i) + { + using (MeasureTime("BuildMesh")) + { + MeshWithMaterials meshWithMaterials; + if (EnableLoadBalancing) + { + var buildMesh = MeshImporter.BuildMeshCoroutine(this, x); + yield return buildMesh; + meshWithMaterials = buildMesh.Current as MeshWithMaterials; + } + else + { + meshWithMaterials = MeshImporter.BuildMesh(this, x); + } + + var mesh = meshWithMaterials.Mesh; + + // mesh name + if (string.IsNullOrEmpty(mesh.name)) + { + mesh.name = string.Format("UniGLTF import#{0}", i); + } + var originalName = mesh.name; + for (int j = 1; Meshes.Any(y => y.Mesh.name == mesh.name); ++j) + { + mesh.name = string.Format("{0}({1})", originalName, j); + } + + yield return meshWithMaterials; + } + } IEnumerator LoadMeshes() { diff --git a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs index e233eeacf..ad73e5829 100644 --- a/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs +++ b/Assets/VRM/UniGLTF/Scripts/IO/MeshImporter.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; @@ -656,6 +657,134 @@ namespace UniGLTF return result; } + + public static IEnumerator BuildMeshCoroutine(ImporterContext ctx, MeshImporter.MeshContext meshContext) + { + if (!meshContext.materialIndices.Any()) + { + meshContext.materialIndices.Add(0); + } + + var mesh = new Mesh(); + mesh.name = meshContext.name; + + if (meshContext.positions.Length > UInt16.MaxValue) + { +#if UNITY_2017_3_OR_NEWER + mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; +#else + Debug.LogWarningFormat("vertices {0} exceed 65535. not implemented. Unity2017.3 supports large mesh", + meshContext.positions.Length); +#endif + } + + + mesh.vertices = meshContext.positions; + bool recalculateNormals = false; + if (meshContext.normals != null && meshContext.normals.Length > 0) + { + + mesh.normals = meshContext.normals; + } + else + { + recalculateNormals = true; + } + + if (meshContext.uv != null && meshContext.uv.Length > 0) + { + + mesh.uv = meshContext.uv; + } + + bool recalculateTangents = true; +#if UNIGLTF_IMPORT_TANGENTS + if (meshContext.tangents != null && meshContext.tangents.Length > 0) + { + mesh.tangents = meshContext.tangents; + recalculateTangents = false; + } +#endif + + if (meshContext.colors != null && meshContext.colors.Length > 0) + { + + mesh.colors = meshContext.colors; + } + if (meshContext.boneWeights != null && meshContext.boneWeights.Count > 0) + { + mesh.boneWeights = meshContext.boneWeights.ToArray(); + } + mesh.subMeshCount = meshContext.subMeshes.Count; + for (int i = 0; i < meshContext.subMeshes.Count; ++i) + { + mesh.SetTriangles(meshContext.subMeshes[i], i); + } + + if (recalculateNormals) + { + mesh.RecalculateNormals(); + } + if (recalculateTangents) + { +#if UNITY_5_6_OR_NEWER + yield return null; + mesh.RecalculateTangents(); + yield return null; +#else + CalcTangents(mesh); +#endif + } + + var result = new MeshWithMaterials + { + Mesh = mesh, + Materials = meshContext.materialIndices.Select(x => ctx.GetMaterial(x)).ToArray() + }; + + yield return null; + if (meshContext.blendShapes != null) + { + Vector3[] emptyVertices = null; + + foreach (var blendShape in meshContext.blendShapes) + { + if (blendShape.Positions.Count > 0) + { + if (blendShape.Positions.Count == mesh.vertexCount) + { + mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, + blendShape.Positions.ToArray(), + (meshContext.normals != null && meshContext.normals.Length == mesh.vertexCount && blendShape.Normals.Count() == blendShape.Positions.Count()) ? blendShape.Normals.ToArray() : null, + null + ); + yield return null; + } + else + { + Debug.LogWarningFormat("May be partial primitive has blendShape. Require separate mesh or extend blend shape, but not implemented: {0}", blendShape.Name); + } + } + else + { + if (emptyVertices == null) + { + emptyVertices = new Vector3[mesh.vertexCount]; + } + // Debug.LogFormat("empty blendshape: {0}.{1}", mesh.name, blendShape.Name); + // add empty blend shape for keep blend shape index + mesh.AddBlendShapeFrame(blendShape.Name, FRAME_WEIGHT, + emptyVertices, + null, + null + ); + yield return null; + } + } + } + + yield return result; + } /// /// Meshの法線を元にタンジェントを計算する。