diff --git a/Assets/UniGLTF/Runtime/MeshUtility/BoneMeshEraser.cs b/Assets/UniGLTF/Runtime/MeshUtility/BoneMeshEraser.cs index fd34c2584..88d614ca3 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/BoneMeshEraser.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/BoneMeshEraser.cs @@ -131,7 +131,7 @@ namespace UniGLTF.MeshUtility /// /// /// - public static int[] GetExcludedIndices(int[] indices, BoneWeight[] boneWeights, int[] eraseBoneIndices) + static int[] GetExcludedIndices(int[] indices, BoneWeight[] boneWeights, int[] eraseBoneIndices) { var count = ExcludeTriangles(indices, boneWeights, eraseBoneIndices); var dst = new int[count]; diff --git a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs index b24c16ce1..8ecb955fe 100644 --- a/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs +++ b/Assets/UniGLTF/Runtime/MeshUtility/MeshIntegrator.cs @@ -165,6 +165,12 @@ namespace UniGLTF.MeshUtility public void Push(SkinnedMeshRenderer renderer) { + if (renderer == null) + { + // Debug.LogWarningFormat("{0} was destroyed", renderer); + return; + } + var mesh = renderer.sharedMesh; if (mesh == null) { diff --git a/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs b/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs index af956c287..e8db4b7e7 100644 --- a/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs +++ b/Assets/VRM10/Runtime/Components/VRM10Object/VRM10ObjectFirstPerson.cs @@ -29,7 +29,7 @@ namespace UniVRM10 } } - public static int[] GetBonesThatHasAncestor(SkinnedMeshRenderer smr, Transform ancestor) + static int[] GetBonesThatHasAncestor(SkinnedMeshRenderer smr, Transform ancestor) { var eraseBones = smr.bones .Where(x => x.Ancestor().Any(y => y == ancestor)) @@ -38,24 +38,46 @@ namespace UniVRM10 return eraseBones; } + public static async Task CreateErasedMeshAsync(SkinnedMeshRenderer smr, + Transform firstPersonBone, + IAwaitCaller awaitCaller) + { + var eraseBones = GetBonesThatHasAncestor(smr, firstPersonBone); + if (eraseBones.Any()) + { + return await BoneMeshEraser.CreateErasedMeshAsync(smr.sharedMesh, eraseBones, awaitCaller); + } + else + { + return null; + } + } + // // 頭部を取り除いたモデルを複製する // // renderer: 元になるSkinnedMeshRenderer // eraseBones: 削除対象になるボーンのindex - private async static Task CreateHeadlessMeshAsync(SkinnedMeshRenderer renderer, int[] eraseBones, IAwaitCaller awaitCaller) + public async static Task CreateHeadlessMeshAsync(SkinnedMeshRenderer renderer, + Transform firstPersonBone, IAwaitCaller awaitCaller) { - var mesh = await BoneMeshEraser.CreateErasedMeshAsync(renderer.sharedMesh, eraseBones, awaitCaller); - - var go = new GameObject("_headless_" + renderer.name); - var erased = go.AddComponent(); - erased.enabled = false; // hide - erased.sharedMesh = mesh; - erased.sharedMaterials = renderer.sharedMaterials; - erased.bones = renderer.bones; - erased.rootBone = renderer.rootBone; - - return erased; + var mesh = await CreateErasedMeshAsync(renderer, firstPersonBone, awaitCaller); + if (mesh != null) + { + var go = new GameObject("_headless_" + renderer.name); + var erased = go.AddComponent(); + erased.enabled = false; // hide + erased.sharedMesh = mesh; + erased.sharedMaterials = renderer.sharedMaterials; + erased.bones = renderer.bones; + erased.rootBone = renderer.rootBone; + return erased; + } + else + { + // 削除対象が含まれないので何もしない + return null; + } } bool m_done; @@ -70,14 +92,13 @@ namespace UniVRM10 { if (x.GetRenderer(go.transform) is SkinnedMeshRenderer smr) { - var eraseBones = GetBonesThatHasAncestor(smr, firstPersonBone); - if (eraseBones.Any()) - { - // オリジナルのモデルを3人称用にする - smr.gameObject.layer = layer.ThirdPersonOnly; + // オリジナルのモデルを3人称用にする + smr.gameObject.layer = layer.ThirdPersonOnly; - // 頭を取り除いた複製モデルを作成し、1人称用にする - var headless = await CreateHeadlessMeshAsync(smr, eraseBones, awaitCaller); + // 頭を取り除いた複製モデルを作成し、1人称用にする + var headless = await CreateHeadlessMeshAsync(smr, firstPersonBone, awaitCaller); + if (headless != null) + { headless.gameObject.layer = layer.FirstPersonOnly; headless.transform.SetParent(smr.transform, false); if (runtime != null) @@ -85,10 +106,6 @@ namespace UniVRM10 runtime.AddRenderer(headless); } } - else - { - // 削除対象が含まれないので何もしない - } } else if (x.GetRenderer(go.transform) is MeshRenderer mr) { diff --git a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs index 7f3a6fa91..39614d2d9 100644 --- a/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs +++ b/Assets/VRM10/Runtime/MeshUtility/Vrm10MeshUtility.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using UniGLTF; -using UniGLTF.Extensions.VRMC_vrm; using UniGLTF.MeshUtility; using UniHumanoid; using UnityEngine; @@ -122,6 +120,10 @@ namespace UniVRM10 void RemoveComponent(T c) where T : Component { + if (c == null) + { + return; + } var t = c.transform; if (Application.isPlaying) { @@ -225,12 +227,40 @@ namespace UniVRM10 { // TODO: UNDO + var results = new List(); foreach (var group in copy) { var result = MeshIntegrator.Integrate(group, SplitByBlendShape ? MeshIntegrator.BlendShapeOperation.Split : MeshIntegrator.BlendShapeOperation.None); + results.Add(result); + result.AddIntegratedRendererTo(go); + + if (generateFirstPerson && group.Name == "auto") + { + Debug.Log("generateFirstPerson"); + var firstPersonBone = vrmInstance.Humanoid.Head; + var task = VRM10ObjectFirstPerson.CreateErasedMeshAsync( + result.IntegratedRenderer, + firstPersonBone, + new ImmediateCaller()); + task.Wait(); + + if (task.Result != null) + { + result.IntegratedRenderer.sharedMesh = task.Result; + result.IntegratedRenderer.name = "auto.headless"; + } + else + { + Debug.LogWarning("no result"); + } + } + } + + foreach (var result in results) + { foreach (var r in result.SourceMeshRenderers) { RemoveComponent(r); @@ -239,27 +269,6 @@ namespace UniVRM10 { RemoveComponent(r); } - - result.AddIntegratedRendererTo(go); - - if (generateFirstPerson && group.Name == "auto") - { - var firstPersonBone = vrmInstance.Humanoid.Head; - var eraseBones = VRM10ObjectFirstPerson.GetBonesThatHasAncestor( - result.IntegratedRenderer, firstPersonBone); - var task = BoneMeshEraser.CreateErasedMeshAsync(result.MeshMap.Integrated, eraseBones, - new ImmediateCaller()); - task.Wait(); - - if (task.Result.vertexCount > 0) - { - var headless = new GameObject("auto.headless"); - var smr = headless.AddComponent(); - smr.sharedMesh = task.Result; - - headless.transform.SetParent(go.transform); - } - } } } }