diff --git a/Scripts/BlendShape/Blinker.cs b/Scripts/BlendShape/Blinker.cs index 3527f285f..4d66dd34c 100644 --- a/Scripts/BlendShape/Blinker.cs +++ b/Scripts/BlendShape/Blinker.cs @@ -25,7 +25,7 @@ namespace VRM [SerializeField] float m_closeSeconds = 0.1f; - Coroutine m_coroutine; + protected Coroutine m_coroutine; //static readonly string BLINK_NAME = BlendShapePreset.Blink.ToString(); @@ -45,7 +45,7 @@ namespace VRM } } - IEnumerator BlinkRoutine() + protected IEnumerator BlinkRoutine() { while (true) { diff --git a/Scripts/BlendShape/Editor/PreviewEditor.cs b/Scripts/BlendShape/Editor/PreviewEditor.cs index aba657e78..65c348b31 100644 --- a/Scripts/BlendShape/Editor/PreviewEditor.cs +++ b/Scripts/BlendShape/Editor/PreviewEditor.cs @@ -84,7 +84,7 @@ namespace VRM { if (m_scene != null) { - Debug.Log("Bake"); + //Debug.Log("Bake"); m_scene.Bake(values, materialValues, weight); } } diff --git a/Scripts/Editor/VRMTest.cs b/Scripts/Editor/VRMTest.cs index f62f0a32b..ffc3ef331 100644 --- a/Scripts/Editor/VRMTest.cs +++ b/Scripts/Editor/VRMTest.cs @@ -59,7 +59,7 @@ public class VRMTest exporter.Export(); // import - context.Json = gltf.ToJson(); + context.ParseJson(gltf.ToJson(), new SimpleStorage()); Debug.LogFormat("{0}", context.Json); gltfImporter.Import(context); diff --git a/Scripts/Format/Editor/VRMHumanoidNormalizerMenu.cs b/Scripts/Format/Editor/VRMHumanoidNormalizerMenu.cs index 183f33616..8d988c774 100644 --- a/Scripts/Format/Editor/VRMHumanoidNormalizerMenu.cs +++ b/Scripts/Format/Editor/VRMHumanoidNormalizerMenu.cs @@ -100,7 +100,7 @@ namespace VRM }).ToArray(); } - foreach (var src in secondary.GetComponents()) + foreach (var src in go.transform.Traverse().SelectMany(x => x.GetComponents())) { var dst = dstSecondary.gameObject.AddComponent(); dst.m_comment = src.m_comment; diff --git a/Scripts/Format/Editor/vrmAssetPostprocessor.cs b/Scripts/Format/Editor/vrmAssetPostprocessor.cs index 6eb821a50..771e608c3 100644 --- a/Scripts/Format/Editor/vrmAssetPostprocessor.cs +++ b/Scripts/Format/Editor/vrmAssetPostprocessor.cs @@ -6,6 +6,7 @@ using UnityEditor; namespace VRM { +#if !VRM_STOP_ASSETPOSTPROCESSOR public class vrmAssetPostprocessor : AssetPostprocessor { static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) @@ -59,4 +60,5 @@ namespace VRM } } } +#endif } diff --git a/Scripts/Format/VRMExporter.cs b/Scripts/Format/VRMExporter.cs index abdc32d42..49c5e7f59 100644 --- a/Scripts/Format/VRMExporter.cs +++ b/Scripts/Format/VRMExporter.cs @@ -16,7 +16,13 @@ namespace VRM { var gltf = new glTF_VRM(); gltf.asset.generator = string.Format("UniVRM-{0}.{1}", VRMVersion.MAJOR, VRMVersion.MINOR); - using (var exporter = new VRMExporter(gltf)) + using (var exporter = new VRMExporter(gltf) + { +#if VRM_EXPORTER_USE_SPARSE + // experimental + UseSparseAccessorForBlendShape=true +#endif + }) { _Export(gltf, exporter, go); @@ -99,60 +105,10 @@ namespace VRM } // secondary - var secondary = exporter.Copy.transform.Find("secondary"); - if (secondary == null) - { - secondary = exporter.Copy.transform; - } - - var colliders = new List(); - foreach (var vrmColliderGroup in exporter.Copy.transform.Traverse().Select(x => x.GetComponent()).Where(x => x != null)) - { - colliders.Add(vrmColliderGroup); - - var colliderGroup = new glTF_VRM_SecondaryAnimationColliderGroup - { - node = exporter.Nodes.IndexOf(vrmColliderGroup.transform) - }; - - colliderGroup.colliders = vrmColliderGroup.Colliders.Select(x => - { - return new glTF_VRM_SecondaryAnimationCollider - { - offset = x.Offset, - radius = x.Radius, - }; - - }).ToList(); - - gltf.extensions.VRM.secondaryAnimation.colliderGroups.Add(colliderGroup); - } - - foreach (var spring in secondary.GetComponents()) - { - gltf.extensions.VRM.secondaryAnimation.boneGroups.Add(new glTF_VRM_SecondaryAnimationGroup - { - comment = spring.m_comment, - center = exporter.Nodes.IndexOf(spring.m_center), - dragForce = spring.m_dragForce, - gravityDir = spring.m_gravityDir, - gravityPower = spring.m_gravityPower, - stiffiness = spring.m_stiffnessForce, - hitRadius = spring.m_hitRadius, - colliderGroups = spring.ColliderGroups - .Select(x => - { - var index = colliders.IndexOf(x); - if (index == -1) - { - throw new IndexOutOfRangeException(); - } - return index; - }) - .ToArray(), - bones = spring.RootBones.Select(x => exporter.Nodes.IndexOf(x)).ToArray(), - }); - } + VRMSpringUtility.ExportSecondary(exporter.Copy.transform, exporter.Nodes, + x => gltf.extensions.VRM.secondaryAnimation.colliderGroups.Add(x), + x => gltf.extensions.VRM.secondaryAnimation.boneGroups.Add(x) + ); // meta(obsolete) { diff --git a/Scripts/Format/VRMImporter.cs b/Scripts/Format/VRMImporter.cs index 18b8ca90a..8f10fb7e5 100644 --- a/Scripts/Format/VRMImporter.cs +++ b/Scripts/Format/VRMImporter.cs @@ -78,8 +78,8 @@ namespace VRM public static CreateMaterialFunc GetMaterialFunc(List materials) { - var CreateDefault = gltfImporter.CreateMaterialFuncFromShader(Shader.Find("VRM/UnlitTexture")); - var CreateZWrite = gltfImporter.CreateMaterialFuncFromShader(Shader.Find("VRM/UnlitTransparentZWrite")); + var CreateDefault = gltfImporter.CreateMaterialFuncFromShader(new ShaderStore("VRM/UnlitTexture")); + var CreateZWrite = gltfImporter.CreateMaterialFuncFromShader(new ShaderStore("VRM/UnlitTransparentZWrite")); CreateMaterialFunc fallback = (ctx, i) => { var vrm = ctx.GLTF as glTF_VRM; @@ -183,7 +183,8 @@ namespace VRM } LoadBlendShapeMaster(context); - LoadSecondaryMotions(context); + VRMSpringUtility.LoadSecondary(context.Root.transform, context.Nodes, + context.VRM.extensions.VRM.secondaryAnimation); LoadFirstPerson(context); return Unit.Default; @@ -230,59 +231,6 @@ namespace VRM lookAtHead.OnImported(context); } - static void LoadSecondaryMotions(VRMImporterContext context) - { - var secondary = context.Root.transform.Find("secondary"); - if (secondary == null) - { - secondary = new GameObject("secondary").transform; - secondary.SetParent(context.Root.transform, false); - } - - var secondaryAnimation = context.VRM.extensions.VRM.secondaryAnimation; - var colliders = new List(); - foreach (var colliderGroup in secondaryAnimation.colliderGroups) - { - var vrmGroup = context.Nodes[colliderGroup.node].gameObject.AddComponent(); - vrmGroup.Colliders = colliderGroup.colliders.Select(x => - { - return new VRMSpringBoneColliderGroup.SphereCollider - { - Offset = x.offset, - Radius = x.radius - }; - }).ToArray(); - colliders.Add(vrmGroup); - } - - if (secondaryAnimation.boneGroups.Count > 0) - { - foreach (var boneGroup in secondaryAnimation.boneGroups) - { - var vrmBoneGroup = secondary.gameObject.AddComponent(); - if (boneGroup.center != -1) - { - vrmBoneGroup.m_center = context.Nodes[boneGroup.center]; - } - vrmBoneGroup.m_comment = boneGroup.comment; - vrmBoneGroup.m_dragForce = boneGroup.dragForce; - vrmBoneGroup.m_gravityDir = boneGroup.gravityDir; - vrmBoneGroup.m_gravityPower = boneGroup.gravityPower; - vrmBoneGroup.m_hitRadius = boneGroup.hitRadius; - vrmBoneGroup.m_stiffnessForce = boneGroup.stiffiness; - if (boneGroup.colliderGroups != null && boneGroup.colliderGroups.Any()) - { - vrmBoneGroup.ColliderGroups = boneGroup.colliderGroups.Select(x => colliders[x]).ToArray(); - } - vrmBoneGroup.RootBones = boneGroup.bones.Select(x => context.Nodes[x]).ToList(); - } - } - else - { - secondary.gameObject.AddComponent(); - } - } - static void LoadBlendShapeMaster(VRMImporterContext context) { context.BlendShapeAvatar = ScriptableObject.CreateInstance(); @@ -457,12 +405,12 @@ namespace VRM #endregion #region LoadVrmAsync - static IEnumerator LoadTextures(VRMImporterContext context) + static IEnumerator LoadTextures(VRMImporterContext context, IStorage storage) { - for(int i=0; i onLoaded) + public static void LoadVrmAsync(string path, Action onLoaded, Action onError = null) { var context = new VRMImporterContext(path); context.ParseVrm(File.ReadAllBytes(path)); - LoadVrmAsync(context, onLoaded); + LoadVrmAsync(context, onLoaded, onError); } - public static void LoadVrmAsync(Byte[] bytes, Action onLoaded) + public static void LoadVrmAsync(Byte[] bytes, Action onLoaded, Action onError = null) { var context = new VRMImporterContext(); context.ParseVrm(bytes); - LoadVrmAsync(context, onLoaded); + LoadVrmAsync(context, onLoaded, onError); } - public static void LoadVrmAsync(VRMImporterContext ctx, Action onLoaded) + public static void LoadVrmAsync(VRMImporterContext ctx, Action onLoaded, Action onError = null) { + if (onError == null) + { + onError = Debug.LogError; + } LoadVrmAsyncInternal(ctx) - .Subscribe(Scheduler.MainThread, onLoaded, Debug.LogError); + .Subscribe(Scheduler.MainThread, onLoaded, onError); } private static Schedulable LoadVrmAsyncInternal(VRMImporterContext ctx) @@ -610,7 +562,7 @@ namespace VRM () => { var texture = new TextureItem(ctx.GLTF, index); - texture.Process(); + texture.Process(ctx.GLTF, ctx.Storage); return texture; }) .ContinueWith(Scheduler.ThreadPool, x => ctx.Textures.Add(x)); diff --git a/Scripts/Format/VRMImporterContext.cs b/Scripts/Format/VRMImporterContext.cs index 20acf4a93..a341fb1ee 100644 --- a/Scripts/Format/VRMImporterContext.cs +++ b/Scripts/Format/VRMImporterContext.cs @@ -58,7 +58,7 @@ namespace VRM if(gltfMeta.texture >= 0 && gltfMeta.texture < VRM.textures.Count) { var t = new TextureItem(VRM, gltfMeta.texture); - t.Process(); + t.Process(VRM, Storage); meta.Thumbnail=t.Texture; } } diff --git a/Scripts/Format/VRMVersion.cs b/Scripts/Format/VRMVersion.cs index 37a6613a5..a095fee18 100644 --- a/Scripts/Format/VRMVersion.cs +++ b/Scripts/Format/VRMVersion.cs @@ -4,11 +4,11 @@ namespace VRM public static partial class VRMVersion { public const int MAJOR = 0; - public const int MINOR = 38; + public const int MINOR = 39; - public const string VERSION = "0.38"; + public const string VERSION = "0.39"; - public const string DecrementMenuName = "VRM/Version(0.38) Decrement"; - public const string IncrementMenuName = "VRM/Version(0.38) Increment"; + public const string DecrementMenuName = "VRM/Version(0.39) Decrement"; + public const string IncrementMenuName = "VRM/Version(0.39) Increment"; } } diff --git a/Scripts/Format/glTF_VRM_Material.cs b/Scripts/Format/glTF_VRM_Material.cs index 8ed73b21f..7e85cbdfc 100644 --- a/Scripts/Format/glTF_VRM_Material.cs +++ b/Scripts/Format/glTF_VRM_Material.cs @@ -10,6 +10,7 @@ using UnityEditor; namespace VRM { + [Serializable] public class glTF_VRM_Material : UniGLTF.JsonSerializableBase { public string name; @@ -98,7 +99,7 @@ namespace VRM return materials; } - public static glTF_VRM_Material CreateFromMaterial(Material m, List textures) + public static glTF_VRM_Material CreateFromMaterial(Material m, List textures) { var material = new glTF_VRM_Material { @@ -131,7 +132,7 @@ namespace VRM case ShaderUtil.ShaderPropertyType.TexEnv: { - var texture = m.GetTexture(name) as Texture2D; + var texture = m.GetTexture(name); if (texture != null) { var value = textures.IndexOf(texture); diff --git a/Scripts/SkinnedMeshUtility/Editor/BoneNormalizer.cs b/Scripts/SkinnedMeshUtility/Editor/BoneNormalizer.cs index 09d7bd788..ad297ebf8 100644 --- a/Scripts/SkinnedMeshUtility/Editor/BoneNormalizer.cs +++ b/Scripts/SkinnedMeshUtility/Editor/BoneNormalizer.cs @@ -170,7 +170,30 @@ namespace VRM { mesh.SetIndices(srcMesh.GetIndices(i), srcMesh.GetTopology(i), i); } - mesh.boneWeights = srcMesh.boneWeights; + + // boneweights + var bones = srcRenderer.bones.Select(x => boneMap[x]).ToArray(); + if (bones.Length > 0) + { + mesh.boneWeights = srcMesh.boneWeights; + } + else + { + Debug.LogFormat("no weight: {0}", srcMesh.name); + bones = new[] { boneMap[srcRenderer.transform] }; + var bw = new BoneWeight + { + boneIndex0 = 0, + boneIndex1 = 0, + boneIndex2 = 0, + boneIndex3 = 0, + weight0 = 1.0f, + weight1 = 0.0f, + weight2 = 0.0f, + weight3 = 0.0f, + }; + mesh.boneWeights = Enumerable.Range(0, srcMesh.vertexCount).Select(x => bw).ToArray(); + } var meshVertices = mesh.vertices; var meshNormals = mesh.normals; @@ -270,7 +293,6 @@ namespace VRM } // recalc bindposes - var bones = srcRenderer.bones.Select(x => boneMap[x]).ToArray(); mesh.bindposes = bones.Select(x => x.worldToLocalMatrix * dst.transform.localToWorldMatrix).ToArray(); diff --git a/Scripts/SpringBone/VRMSpringUtility.cs b/Scripts/SpringBone/VRMSpringUtility.cs new file mode 100644 index 000000000..a22677dcb --- /dev/null +++ b/Scripts/SpringBone/VRMSpringUtility.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF; +using UnityEngine; +using System.IO; +using System.Text; +#if UNITY_EDITOR +using UnityEditor; +#endif + + +namespace VRM +{ + public static class VRMSpringUtility + { +#if UNITY_EDITOR + #region save + [MenuItem("VRM/SaveSpringBoneToJSON", validate = true)] + static bool SaveSpringBoneToJSONIsEnable() + { + var root = Selection.activeObject as GameObject; + if (root == null) + { + return false; + } + + var animator = root.GetComponent(); + if (animator == null) + { + return false; + } + + return true; + } + + [MenuItem("VRM/SaveSpringBoneToJSON")] + static void SaveSpringBoneToJSON() + { + var path = EditorUtility.SaveFilePanel( + "Save spring to json", + null, + "VRMSpring.json", + "json"); + if (string.IsNullOrEmpty(path)) + { + return; + } + + var go = Selection.activeObject as GameObject; + var root = go.transform; + var nodes = root.Traverse().Skip(1).ToList(); + var spring = new glTF_VRM_SecondaryAnimation(); + ExportSecondary(root, nodes, + spring.colliderGroups.Add, + spring.boneGroups.Add + ); + + File.WriteAllText(path, spring.ToJson(), Encoding.UTF8); + } + + #endregion + + #region load + [MenuItem("VRM/LoadSpringBoneFromJSON", true)] + static bool LoadSpringBoneFromJSONIsEnable() + { + var root = Selection.activeObject as GameObject; + if (root == null) + { + return false; + } + + var animator = root.GetComponent(); + if (animator == null) + { + return false; + } + + return true; + } + + [MenuItem("VRM/LoadSpringBoneFromJSON")] + static void LoadSpringBoneFromJSON() + { + var path = EditorUtility.OpenFilePanel( + "Load spring from json", + null, + "json"); + if (string.IsNullOrEmpty(path)) + { + return; + } + + var json = File.ReadAllText(path, Encoding.UTF8); + var spring = JsonUtility.FromJson(json); + + var go = Selection.activeObject as GameObject; + var root = go.transform; + var nodes = root.Traverse().Skip(1).ToList(); + + LoadSecondary(root, nodes, spring); + } + #endregion +#endif + + public static void ExportSecondary(Transform root, List nodes, + Action addSecondaryColliderGroup, + Action addSecondaryGroup) + { + var colliders = new List(); + foreach (var vrmColliderGroup in root.Traverse() + .Select(x => x.GetComponent()) + .Where(x => x != null)) + { + colliders.Add(vrmColliderGroup); + + var colliderGroup = new glTF_VRM_SecondaryAnimationColliderGroup + { + node = nodes.IndexOf(vrmColliderGroup.transform) + }; + + colliderGroup.colliders = vrmColliderGroup.Colliders.Select(x => + { + return new glTF_VRM_SecondaryAnimationCollider + { + offset = x.Offset, + radius = x.Radius, + }; + + }).ToList(); + + addSecondaryColliderGroup(colliderGroup); + } + + foreach (var spring in root.Traverse() + .SelectMany(x => x.GetComponents()) + .Where(x => x != null)) + { + addSecondaryGroup(new glTF_VRM_SecondaryAnimationGroup + { + comment = spring.m_comment, + center = nodes.IndexOf(spring.m_center), + dragForce = spring.m_dragForce, + gravityDir = spring.m_gravityDir, + gravityPower = spring.m_gravityPower, + stiffiness = spring.m_stiffnessForce, + hitRadius = spring.m_hitRadius, + colliderGroups = spring.ColliderGroups + .Select(x => + { + var index = colliders.IndexOf(x); + if (index == -1) + { + throw new IndexOutOfRangeException(); + } + return index; + }) + .ToArray(), + bones = spring.RootBones.Select(x => nodes.IndexOf(x)).ToArray(), + }); + } + } + + public static void LoadSecondary(Transform root, List nodes, + glTF_VRM_SecondaryAnimation secondaryAnimation) + { + var secondary = root.Find("secondary"); + if (secondary == null) + { + secondary = new GameObject("secondary").transform; + secondary.SetParent(root, false); + } + + // clear components + var remove = root.Traverse() + .SelectMany(x => x.GetComponents()) + .Where(x => x is VRMSpringBone || x is VRMSpringBoneColliderGroup) + .ToArray(); + foreach(var x in remove) + { + if (Application.isPlaying) + { + GameObject.Destroy(x); + } + else + { + GameObject.DestroyImmediate(x); + } + } + + //var secondaryAnimation = context.VRM.extensions.VRM.secondaryAnimation; + var colliders = new List(); + foreach (var colliderGroup in secondaryAnimation.colliderGroups) + { + var vrmGroup = nodes[colliderGroup.node].gameObject.AddComponent(); + vrmGroup.Colliders = colliderGroup.colliders.Select(x => + { + return new VRMSpringBoneColliderGroup.SphereCollider + { + Offset = x.offset, + Radius = x.radius + }; + }).ToArray(); + colliders.Add(vrmGroup); + } + + if (secondaryAnimation.boneGroups.Count > 0) + { + foreach (var boneGroup in secondaryAnimation.boneGroups) + { + var vrmBoneGroup = secondary.gameObject.AddComponent(); + if (boneGroup.center != -1) + { + vrmBoneGroup.m_center = nodes[boneGroup.center]; + } + vrmBoneGroup.m_comment = boneGroup.comment; + vrmBoneGroup.m_dragForce = boneGroup.dragForce; + vrmBoneGroup.m_gravityDir = boneGroup.gravityDir; + vrmBoneGroup.m_gravityPower = boneGroup.gravityPower; + vrmBoneGroup.m_hitRadius = boneGroup.hitRadius; + vrmBoneGroup.m_stiffnessForce = boneGroup.stiffiness; + if (boneGroup.colliderGroups != null && boneGroup.colliderGroups.Any()) + { + vrmBoneGroup.ColliderGroups = boneGroup.colliderGroups.Select(x => colliders[x]).ToArray(); + } + vrmBoneGroup.RootBones = boneGroup.bones.Select(x => nodes[x]).ToList(); + } + } + else + { + secondary.gameObject.AddComponent(); + } + } + + } +} diff --git a/Scripts/SpringBone/VRMSpringUtility.cs.meta b/Scripts/SpringBone/VRMSpringUtility.cs.meta new file mode 100644 index 000000000..773a15d4c --- /dev/null +++ b/Scripts/SpringBone/VRMSpringUtility.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 42564d357aca11d4882ab504d7f99166 +timeCreated: 1528358605 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UniGLTF b/UniGLTF index c8b19d3b8..1d41ff08c 160000 --- a/UniGLTF +++ b/UniGLTF @@ -1 +1 @@ -Subproject commit c8b19d3b8332cadff434a58646610abe2618f3c8 +Subproject commit 1d41ff08c25707e9b789997368bac2971f2cd78e