using System; using System.Collections.Generic; using System.Linq; using Unity.Collections; using UnityEngine; using UnityEngine.Profiling; using UniGLTF.SpringBoneJobs.Blittables; namespace UniGLTF.SpringBoneJobs.InputPorts { /// /// ひとつのVRMに紐づくFastSpringBoneに関連したバッファを保持するクラス /// public class FastSpringBoneBuffer : IDisposable { /// /// model root /// public Transform Model { get; } // NOTE: これらはFastSpringBoneBufferCombinerによってバッチングされる public NativeArray Springs { get; } public NativeArray Joints { get; } public NativeArray Colliders { get; } public NativeArray Logics { get; } public NativeArray BlittableTransforms { get; } public Transform[] Transforms { get; } public bool IsDisposed { get; private set; } /// /// Joint, Collider, Center の Transform のリスト /// - 重複を除去 /// /// /// static Transform[] MakeFlattenTransformList(FastSpringBoneSpring[] springs) { var transformHashSet = new HashSet(); foreach (var spring in springs) { foreach (var joint in spring.joints) { transformHashSet.Add(joint.Transform); if (joint.Transform.parent != null) transformHashSet.Add(joint.Transform.parent); } foreach (var collider in spring.colliders) { transformHashSet.Add(collider.Transform); } if (spring.center != null) transformHashSet.Add(spring.center); } var Transforms = transformHashSet.ToArray(); return Transforms; } public FastSpringBoneBuffer(Transform model, FastSpringBoneSpring[] springs) { Model = model; Profiler.BeginSample("FastSpringBone.ConstructBuffers.BufferBuilder"); Transforms = MakeFlattenTransformList(springs); List blittableSprings = new(); List blittableJoints = new(); List blittableColliders = new(); List blittableLogics = new(); foreach (var spring in springs) { var blittableSpring = new BlittableSpring { colliderSpan = new BlittableSpan { startIndex = blittableColliders.Count, count = spring.colliders.Length, }, logicSpan = new BlittableSpan { startIndex = blittableJoints.Count, count = spring.joints.Length - 1, }, centerTransformIndex = Array.IndexOf(Transforms, spring.center), }; blittableSprings.Add(blittableSpring); blittableColliders.AddRange(spring.colliders.Select(collider => { var blittable = collider.Collider; blittable.transformIndex = Array.IndexOf(Transforms, collider.Transform); return blittable; })); blittableJoints.AddRange(spring.joints .Take(spring.joints.Length - 1).Select(joint => { var blittable = joint.Joint; return blittable; })); blittableLogics.AddRange(LogicFromTransform(Transforms, spring)); } Springs = new NativeArray(blittableSprings.ToArray(), Allocator.Persistent); Joints = new NativeArray(blittableJoints.ToArray(), Allocator.Persistent); Colliders = new NativeArray(blittableColliders.ToArray(), Allocator.Persistent); Logics = new NativeArray(blittableLogics.ToArray(), Allocator.Persistent); BlittableTransforms = new NativeArray(Transforms.Length, Allocator.Persistent); Profiler.EndSample(); } /// /// Transform の現状から Logic を作成する。 /// /// /// /// joint index /// public static IEnumerable LogicFromTransform(Transform[] Transforms, FastSpringBoneSpring spring) { // vrm-1.0 では末端の joint は tail で処理対象でないのに注意! for (int i = 0; i < spring.joints.Length - 1; ++i) { var joint = spring.joints[i]; var tailJoint = spring.joints[i + 1]; var localPosition = tailJoint.Transform.localPosition; var scale = tailJoint.Transform.lossyScale; var localChildPosition = new Vector3( localPosition.x * scale.x, localPosition.y * scale.y, localPosition.z * scale.z ); yield return new BlittableJointImmutable { headTransformIndex = Array.IndexOf(Transforms, joint.Transform), parentTransformIndex = Array.IndexOf(Transforms, joint.Transform.parent), tailTransformIndex = Array.IndexOf(Transforms, tailJoint.Transform), localRotation = joint.DefaultLocalRotation, boneAxis = localChildPosition.normalized, length = localChildPosition.magnitude }; } } public void Dispose() { if (IsDisposed) return; IsDisposed = true; Springs.Dispose(); Joints.Dispose(); BlittableTransforms.Dispose(); Colliders.Dispose(); Logics.Dispose(); } } }