using System; using System.Collections.Generic; using System.Linq; using UniGLTF; using UnityEngine; using System.IO; using System.Text; using UnityEditor; namespace VRM { public static class VRMSpringUtility { 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)) { var index = nodes.IndexOf(vrmColliderGroup.transform); if (index == -1) { continue; } colliders.Add(vrmColliderGroup); var colliderGroup = new glTF_VRM_SecondaryAnimationColliderGroup { node = index }; 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 => colliders.IndexOf(x)) .Where(x => x != -1) .ToArray(), bones = spring.RootBones.Select(x => nodes.IndexOf(x)).ToArray(), }); } } /// /// Node getter. If not found, Never throw, return false. /// public delegate bool TryGetNode(int index, out Transform transform); public static void LoadSecondary(Transform root, TryGetNode tryGetNode, glTF_VRM_SecondaryAnimation secondaryAnimation) { var secondary = root.Find("secondary"); if (secondary == null) { secondary = new GameObject("secondary").transform; secondary.SetParent(root, false); } // clear components var vrmSpringBones = root.GetComponentsInChildren(); var vrmSpringBoneColliderGroup = root.GetComponentsInChildren(); var length = (vrmSpringBones?.Length ?? 0) + (vrmSpringBoneColliderGroup?.Length ?? 0); var remove = new Component[length]; var index = 0; if (vrmSpringBones != null) { foreach (var vrmSpringBone in vrmSpringBones) { remove[index++] = vrmSpringBone; } } if (vrmSpringBoneColliderGroup != null) { foreach (var vrmSpringBoneCollider in vrmSpringBoneColliderGroup) { remove[index++] = vrmSpringBoneCollider; } } foreach (var x in remove) { if (Application.isPlaying) { GameObject.Destroy(x); } else { GameObject.DestroyImmediate(x); } } var colliders = new List(); foreach (var colliderGroup in secondaryAnimation.colliderGroups) { if (tryGetNode(colliderGroup.node, out var node)) { var vrmGroup = node.gameObject.AddComponent(); vrmGroup.Colliders = colliderGroup.colliders.Select(x => { return new VRMSpringBoneColliderGroup.SphereCollider { Offset = x.offset, Radius = x.radius }; }).ToArray(); colliders.Add(vrmGroup); } else { Debug.LogError("Broken collider group"); break; } } if (secondaryAnimation.boneGroups.Count > 0) { foreach (var boneGroup in secondaryAnimation.boneGroups) { var vrmBoneGroup = secondary.gameObject.AddComponent(); if (boneGroup.center != -1 && tryGetNode(boneGroup.center, out var node)) { vrmBoneGroup.m_center = node; } 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 = new VRMSpringBoneColliderGroup[boneGroup.colliderGroups.Length]; for (int i = 0; i < boneGroup.colliderGroups.Length; ++i) { var colliderGroup = boneGroup.colliderGroups[i]; if (colliderGroup >= 0 && colliderGroup < colliders.Count) { vrmBoneGroup.ColliderGroups[i] = colliders[colliderGroup]; } } } var boneList = new List(); foreach (var x in boneGroup.bones) { if (tryGetNode(x, out var boneNode)) { boneList.Add(boneNode); } } vrmBoneGroup.RootBones = boneList; } } else { secondary.gameObject.AddComponent(); } } } }