From ef06850e17bdf3d692b5e9a4339bf2044b404187 Mon Sep 17 00:00:00 2001 From: mkc1370 Date: Fri, 29 Jul 2022 10:06:24 +0900 Subject: [PATCH 1/5] fixed BlendShapeAvatar.Clips not to contain null --- .../Runtime/BlendShape/BlendShapeAvatar.cs | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs b/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs index 6129050e3..814fe574f 100644 --- a/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs +++ b/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using UniGLTF; using System.IO; +using UnityEngine.Serialization; #if UNITY_EDITOR using UnityEditor; #endif @@ -13,23 +14,34 @@ namespace VRM [CreateAssetMenu(menuName = "VRM/BlendShapeAvatar")] public class BlendShapeAvatar : ScriptableObject { + [FormerlySerializedAs("Clips")] [SerializeField] - public List Clips = new List(); + private List clips = new List(); + + public List Clips + { + get + { + RemoveNullClip(); + return clips; + } + set => clips = value; + } /// /// NullのClipを削除して詰める /// public void RemoveNullClip() { - if (Clips == null) + if (clips == null) { return; } - for (int i = Clips.Count - 1; i >= 0; --i) + for (int i = clips.Count - 1; i >= 0; --i) { - if (Clips[i] == null) + if (clips[i] == null) { - Clips.RemoveAt(i); + clips.RemoveAt(i); } } } From 5522fa56f800d675dd3b7acff69b7e7aa9a9680d Mon Sep 17 00:00:00 2001 From: mkc1370 Date: Fri, 29 Jul 2022 10:08:10 +0900 Subject: [PATCH 2/5] change RemoveNullClip to private --- Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs | 2 -- Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs b/Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs index ae66a99d1..1ba81c499 100644 --- a/Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs +++ b/Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs @@ -46,8 +46,6 @@ namespace VRM public BlendShapeClipSelector(BlendShapeAvatar avatar, Action onSelected) { - avatar.RemoveNullClip(); - m_avatar = avatar; m_onSelected = onSelected; diff --git a/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs b/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs index 814fe574f..7e07b0b57 100644 --- a/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs +++ b/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs @@ -31,7 +31,7 @@ namespace VRM /// /// NullのClipを削除して詰める /// - public void RemoveNullClip() + private void RemoveNullClip() { if (clips == null) { From 10256bd76e4d7954d05c326879b7762298d8c4b5 Mon Sep 17 00:00:00 2001 From: mkc1370 Date: Fri, 29 Jul 2022 18:22:34 +0900 Subject: [PATCH 3/5] Revert "change RemoveNullClip to private" This reverts commit 5522fa56f800d675dd3b7acff69b7e7aa9a9680d. --- Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs | 2 ++ Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs b/Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs index 1ba81c499..ae66a99d1 100644 --- a/Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs +++ b/Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs @@ -46,6 +46,8 @@ namespace VRM public BlendShapeClipSelector(BlendShapeAvatar avatar, Action onSelected) { + avatar.RemoveNullClip(); + m_avatar = avatar; m_onSelected = onSelected; diff --git a/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs b/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs index 7e07b0b57..814fe574f 100644 --- a/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs +++ b/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs @@ -31,7 +31,7 @@ namespace VRM /// /// NullのClipを削除して詰める /// - private void RemoveNullClip() + public void RemoveNullClip() { if (clips == null) { From f1de67b3393ca8e4af6d82886ca515943b5854e2 Mon Sep 17 00:00:00 2001 From: mkc1370 Date: Fri, 29 Jul 2022 18:23:03 +0900 Subject: [PATCH 4/5] Revert "fixed BlendShapeAvatar.Clips not to contain null" This reverts commit ef06850e17bdf3d692b5e9a4339bf2044b404187. --- .../Runtime/BlendShape/BlendShapeAvatar.cs | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs b/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs index 814fe574f..6129050e3 100644 --- a/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs +++ b/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using UniGLTF; using System.IO; -using UnityEngine.Serialization; #if UNITY_EDITOR using UnityEditor; #endif @@ -14,34 +13,23 @@ namespace VRM [CreateAssetMenu(menuName = "VRM/BlendShapeAvatar")] public class BlendShapeAvatar : ScriptableObject { - [FormerlySerializedAs("Clips")] [SerializeField] - private List clips = new List(); - - public List Clips - { - get - { - RemoveNullClip(); - return clips; - } - set => clips = value; - } + public List Clips = new List(); /// /// NullのClipを削除して詰める /// public void RemoveNullClip() { - if (clips == null) + if (Clips == null) { return; } - for (int i = clips.Count - 1; i >= 0; --i) + for (int i = Clips.Count - 1; i >= 0; --i) { - if (clips[i] == null) + if (Clips[i] == null) { - clips.RemoveAt(i); + Clips.RemoveAt(i); } } } From 8df51422ef51cbd0b914764ca44a0911cee875a0 Mon Sep 17 00:00:00 2001 From: mkc1370 Date: Fri, 29 Jul 2022 20:16:17 +0900 Subject: [PATCH 5/5] add null check --- .../BlendShape/BlendShapeClipSelector.cs | 2 -- .../BlendShape/VRMBlendShapeProxyValidator.cs | 6 ++++++ .../Editor/Format/VRMBlendShapeExportFilter.cs | 8 +++++++- Assets/VRM/Editor/Format/VRMEditorExporter.cs | 10 ++++++++-- Assets/VRM/Editor/Format/VRMExporterWizard.cs | 8 ++++---- .../VRM/Runtime/BlendShape/BlendShapeAvatar.cs | 18 ------------------ .../Tests/SampleTests/VRMImportExportTests.cs | 4 ++++ .../BlendShapeMenu/BlendShapeMenu.cs | 2 +- 8 files changed, 30 insertions(+), 28 deletions(-) diff --git a/Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs b/Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs index ae66a99d1..1ba81c499 100644 --- a/Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs +++ b/Assets/VRM/Editor/BlendShape/BlendShapeClipSelector.cs @@ -46,8 +46,6 @@ namespace VRM public BlendShapeClipSelector(BlendShapeAvatar avatar, Action onSelected) { - avatar.RemoveNullClip(); - m_avatar = avatar; m_onSelected = onSelected; diff --git a/Assets/VRM/Editor/BlendShape/VRMBlendShapeProxyValidator.cs b/Assets/VRM/Editor/BlendShape/VRMBlendShapeProxyValidator.cs index 84cb3a2f1..9e7d2c841 100644 --- a/Assets/VRM/Editor/BlendShape/VRMBlendShapeProxyValidator.cs +++ b/Assets/VRM/Editor/BlendShape/VRMBlendShapeProxyValidator.cs @@ -57,6 +57,12 @@ namespace VRM // 参照が生きているか foreach (var c in p.BlendShapeAvatar.Clips) { + if (c == null) + { + yield return Validation.Warning($"BlendShapeName({c.BlendShapeName})'s BlendShapeClip is not found"); + continue; + } + for (int i = 0; i < c.Values.Length; ++i) { var v = c.Values[i]; diff --git a/Assets/VRM/Editor/Format/VRMBlendShapeExportFilter.cs b/Assets/VRM/Editor/Format/VRMBlendShapeExportFilter.cs index d04f087f0..d1a754262 100644 --- a/Assets/VRM/Editor/Format/VRMBlendShapeExportFilter.cs +++ b/Assets/VRM/Editor/Format/VRMBlendShapeExportFilter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using UniGLTF; using UnityEngine; @@ -11,6 +12,11 @@ namespace VRM { foreach (var c in clips) { + if (c == null) + { + continue; + } + if (onlyPreset) { if (c.Preset == BlendShapePreset.Unknown) @@ -44,7 +50,7 @@ namespace VRM { if (proxy.BlendShapeAvatar != null) { - Clips.AddRange(proxy.BlendShapeAvatar.Clips); + Clips.AddRange(proxy.BlendShapeAvatar.Clips.Where(x => x != null)); } } } diff --git a/Assets/VRM/Editor/Format/VRMEditorExporter.cs b/Assets/VRM/Editor/Format/VRMEditorExporter.cs index 929cc1af3..4c2755d82 100644 --- a/Assets/VRM/Editor/Format/VRMEditorExporter.cs +++ b/Assets/VRM/Editor/Format/VRMEditorExporter.cs @@ -49,6 +49,11 @@ namespace VRM avatar.Clips = new List(); foreach (var clip in src.Clips) { + if (clip == null) + { + continue; + } + if (removeUnknown && clip.Preset == BlendShapePreset.Unknown) { continue; @@ -70,7 +75,8 @@ namespace VRM if (mesh.blendShapeCount == 0) return; // Mesh から BlendShapeClip からの参照がある blendShape の index を集める - var usedBlendshapeIndexArray = copyBlendShapeAvatar.Clips + var copyBlendShapeAvatarClips = copyBlendShapeAvatar.Clips.Where(x => x != null).ToArray(); + var usedBlendshapeIndexArray = copyBlendShapeAvatarClips .SelectMany(clip => clip.Values) .Where(val => target.transform.Find(val.RelativePath) == smr.transform) .Select(val => val.Index) @@ -95,7 +101,7 @@ namespace VRM var indexMapper = usedBlendshapeIndexArray .Select((x, i) => new { x, i }) .ToDictionary(pair => pair.x, pair => pair.i); - foreach (var clip in copyBlendShapeAvatar.Clips) + foreach (var clip in copyBlendShapeAvatarClips) { for (var i = 0; i < clip.Values.Length; ++i) { diff --git a/Assets/VRM/Editor/Format/VRMExporterWizard.cs b/Assets/VRM/Editor/Format/VRMExporterWizard.cs index ba50e49e1..9b50bb218 100644 --- a/Assets/VRM/Editor/Format/VRMExporterWizard.cs +++ b/Assets/VRM/Editor/Format/VRMExporterWizard.cs @@ -358,26 +358,26 @@ namespace VRM return; } - m_merger = new BlendShapeMerger(avatar.Clips, proxy.transform); + m_merger = new BlendShapeMerger(avatar.Clips.Where(x => x != null), proxy.transform); GUILayout.Space(20); EditorGUILayout.HelpBox(BlendShapeTabMessages.SCENE_MESSAGE.Msg(), MessageType.Info); - var options = avatar.Clips.Select(x => x.ToString()).ToArray(); + var options = avatar.Clips.Where(x => x != null).Select(x => x.ToString()).ToArray(); m_selected = EditorGUILayout.Popup("select blendshape", m_selected, options); if (GUILayout.Button(BlendShapeTabMessages.APPLY_BLENDSHAPECLIP_BUTTON.Msg())) { - m_merger.SetValues(avatar.Clips.Select((x, i) => new KeyValuePair(x.Key, i == m_selected ? 1 : 0))); + m_merger.SetValues(avatar.Clips.Where(x => x != null).Select((x, i) => new KeyValuePair(x.Key, i == m_selected ? 1 : 0))); m_merger.Apply(); m_settings.PoseFreeze = true; } if (GUILayout.Button(BlendShapeTabMessages.CLEAR_BLENDSHAPE_BUTTON.Msg())) { - m_merger.SetValues(avatar.Clips.Select(x => new KeyValuePair(x.Key, 0))); + m_merger.SetValues(avatar.Clips.Where(x => x != null).Select(x => new KeyValuePair(x.Key, 0))); m_merger.Apply(); } } diff --git a/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs b/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs index 6129050e3..a5a416569 100644 --- a/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs +++ b/Assets/VRM/Runtime/BlendShape/BlendShapeAvatar.cs @@ -16,24 +16,6 @@ namespace VRM [SerializeField] public List Clips = new List(); - /// - /// NullのClipを削除して詰める - /// - public void RemoveNullClip() - { - if (Clips == null) - { - return; - } - for (int i = Clips.Count - 1; i >= 0; --i) - { - if (Clips[i] == null) - { - Clips.RemoveAt(i); - } - } - } - #if UNITY_EDITOR [ContextMenu("Restore")] void Restore() diff --git a/Assets/VRM/Tests/SampleTests/VRMImportExportTests.cs b/Assets/VRM/Tests/SampleTests/VRMImportExportTests.cs index 22b106e36..fae94b210 100644 --- a/Assets/VRM/Tests/SampleTests/VRMImportExportTests.cs +++ b/Assets/VRM/Tests/SampleTests/VRMImportExportTests.cs @@ -113,6 +113,10 @@ namespace VRM.Samples { var gltfBlendShapeClip = context.VRM.blendShapeMaster.blendShapeGroups[i]; var unityBlendShapeClip = blendshapeProxy.BlendShapeAvatar.Clips[i]; + if (unityBlendShapeClip == null) + { + continue; + } Assert.AreEqual(Enum.Parse(typeof(BlendShapePreset), gltfBlendShapeClip.presetName, true), unityBlendShapeClip.Preset); } } diff --git a/Assets/VRM_Samples/BlendShapeMenu/BlendShapeMenu.cs b/Assets/VRM_Samples/BlendShapeMenu/BlendShapeMenu.cs index 096b9ccc0..95ae2a461 100644 --- a/Assets/VRM_Samples/BlendShapeMenu/BlendShapeMenu.cs +++ b/Assets/VRM_Samples/BlendShapeMenu/BlendShapeMenu.cs @@ -103,7 +103,7 @@ namespace VRM.Sample.BlendShapeMenu var sb = new StringBuilder(); foreach (var name in NAMES) { - if (avatar.Clips.Find(x => x.Preset == BlendShapePreset.Unknown && x.BlendShapeName == name)) + if (avatar.Clips.Find(x => x != null && x.Preset == BlendShapePreset.Unknown && x.BlendShapeName == name)) { // already exists continue;