diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeSpringBone .cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeSpringBone .cs index 23dbfff3b..8ede70a88 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeSpringBone .cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10RuntimeSpringBone .cs @@ -14,27 +14,17 @@ namespace UniVRM10 private readonly Vrm10Instance m_instance; private readonly IReadOnlyDictionary m_defaultTransformStates; private readonly FastSpringBoneService m_fastSpringBoneService; - private FastSpringBoneBuffer m_fastSpringBoneBuffer; - private BlittableExternalData m_externalData; + private FastSpringBoneBuffer m_fastSpringBoneBuffer; public Vector3 ExternalForce { - get => m_externalData.ExternalForce; - set - { - m_externalData.ExternalForce = value; - m_fastSpringBoneBuffer.ExternalData = m_externalData; - } + get => m_fastSpringBoneBuffer.ExternalForce; + set { m_fastSpringBoneBuffer.ExternalForce = value; } } - public bool IsSpringBoneEnabled { - get => m_externalData.IsSpringBoneEnabled; - set - { - m_externalData.IsSpringBoneEnabled = value; - m_fastSpringBoneBuffer.ExternalData = m_externalData; - } + get => m_fastSpringBoneBuffer.IsSpringBoneEnabled; + set { m_fastSpringBoneBuffer.IsSpringBoneEnabled = value; } } public Vrm10RuntimeSpringBone(Vrm10Instance instance) @@ -86,39 +76,39 @@ namespace UniVRM10 private FastSpringBoneBuffer CreateFastSpringBoneBuffer(Vrm10InstanceSpringBone springBone) { - return new FastSpringBoneBuffer( - springBone.Springs.Select(spring => new FastSpringBoneSpring - { - center = spring.Center, - colliders = spring.ColliderGroups - .SelectMany(group => group.Colliders) - .Select(collider => new FastSpringBoneCollider - { - Transform = collider.transform, - Collider = new BlittableCollider - { - offset = collider.Offset, - radius = collider.Radius, - tailOrNormal = collider.TailOrNormal, - colliderType = TranslateColliderType(collider.ColliderType) - } - }).ToArray(), - joints = spring.Joints - .Select(joint => new FastSpringBoneJoint - { - Transform = joint.transform, - Joint = new BlittableJoint - { - radius = joint.m_jointRadius, - dragForce = joint.m_dragForce, - gravityDir = joint.m_gravityDir, - gravityPower = joint.m_gravityPower, - stiffnessForce = joint.m_stiffnessForce - }, - DefaultLocalRotation = GetOrAddDefaultTransformState(joint.transform).LocalRotation, - }).ToArray(), - }).ToArray(), - m_externalData); + var b = new FastSpringBoneBufferBuilder(springBone.Springs.Select(spring => new FastSpringBoneSpring + { + center = spring.Center, + colliders = spring.ColliderGroups + .SelectMany(group => group.Colliders) + .Select(collider => new FastSpringBoneCollider + { + Transform = collider.transform, + Collider = new BlittableCollider + { + offset = collider.Offset, + radius = collider.Radius, + tailOrNormal = collider.TailOrNormal, + colliderType = TranslateColliderType(collider.ColliderType) + } + }).ToArray(), + joints = spring.Joints + .Select(joint => new FastSpringBoneJoint + { + Transform = joint.transform, + Joint = new BlittableJoint + { + radius = joint.m_jointRadius, + dragForce = joint.m_dragForce, + gravityDir = joint.m_gravityDir, + gravityPower = joint.m_gravityPower, + stiffnessForce = joint.m_stiffnessForce + }, + DefaultLocalRotation = GetOrAddDefaultTransformState(joint.transform).LocalRotation, + }).ToArray(), + })); + + return new FastSpringBoneBuffer(b); } private TransformState GetOrAddDefaultTransformState(Transform tf) diff --git a/Assets/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBuffer.cs b/Assets/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBuffer.cs index c91391354..3ae2fcbc5 100644 --- a/Assets/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBuffer.cs +++ b/Assets/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBuffer.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using UnityEngine; @@ -26,149 +24,48 @@ namespace UniVRM10.FastSpringBones.System // NOTE: これは更新頻度が高くバッチングが難しいため、ランダムアクセスを許容してメモリへ直接アクセスする // 生のヒープ領域は扱いにくいので長さ1のNativeArrayで代用 private NativeArray _externalData; - - public BlittableExternalData ExternalData + public Vector3 ExternalForce { - get => _externalData[0]; - set => _externalData[0] = value; + get => _externalData[0].ExternalForce; + set + { + _externalData[0] = new BlittableExternalData + { + ExternalForce = value, + IsSpringBoneEnabled = _externalData[0].IsSpringBoneEnabled, + }; + } + } + public bool IsSpringBoneEnabled + { + get => _externalData[0].IsSpringBoneEnabled; + set + { + _externalData[0] = new BlittableExternalData + { + ExternalForce = _externalData[0].ExternalForce, + IsSpringBoneEnabled = value, + }; + } + } - public unsafe FastSpringBoneBuffer(IReadOnlyList springs, - BlittableExternalData externalData, - bool simulateLastBone = false) + public unsafe FastSpringBoneBuffer(FastSpringBoneBufferBuilder b) { - Profiler.BeginSample("FastSpringBone.ConstructBuffers"); - - _externalData = new NativeArray(1, Allocator.Persistent); - ExternalData = externalData; - - // Transformの列挙 - Profiler.BeginSample("FastSpringBone.ConstructBuffers.ConstructTransformBuffer"); - 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(); - var transformIndexDictionary = transforms.Select((trs, index) => (trs, index)) - .ToDictionary(tuple => tuple.trs, tuple => tuple.index); - Profiler.EndSample(); - - // 各種bufferの構築 - Profiler.BeginSample("FastSpringBone.ConstructBuffers.ConstructBuffers"); - var blittableColliders = new List(); - var blittableJoints = new List(); - var blittableSprings = new List(); - var blittableLogics = new List(); - - 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 = simulateLastBone ? spring.joints.Length : spring.joints.Length - 1, - }, - centerTransformIndex = spring.center ? transformIndexDictionary[spring.center] : -1, - ExternalData = (BlittableExternalData*) _externalData.GetUnsafePtr() - }; - blittableSprings.Add(blittableSpring); - - blittableColliders.AddRange(spring.colliders.Select(collider => - { - var blittable = collider.Collider; - blittable.transformIndex = transformIndexDictionary[collider.Transform]; - return blittable; - })); - blittableJoints.AddRange(spring.joints - .Take(simulateLastBone ? spring.joints.Length : spring.joints.Length - 1).Select(joint => - { - var blittable = joint.Joint; - return blittable; - })); - - for (var i = 0; i < (simulateLastBone ? spring.joints.Length : spring.joints.Length - 1); ++i) - { - var joint = spring.joints[i]; - var tailJoint = i + 1 < spring.joints.Length ? spring.joints[i + 1] : (FastSpringBoneJoint?) null; - var parentJoint = i - 1 >= 0 ? spring.joints[i - 1] : (FastSpringBoneJoint?) null; - var localPosition = Vector3.zero; - if (tailJoint.HasValue) - { - localPosition = tailJoint.Value.Transform.localPosition; - } - else - { - if (parentJoint.HasValue) - { - var delta = joint.Transform.position - parentJoint.Value.Transform.position; - localPosition = - joint.Transform.worldToLocalMatrix.MultiplyPoint(joint.Transform.position + delta); - } - else - { - localPosition = Vector3.down; - } - } - - var scale = tailJoint.HasValue ? tailJoint.Value.Transform.lossyScale : joint.Transform.lossyScale; - var localChildPosition = - new Vector3( - localPosition.x * scale.x, - localPosition.y * scale.y, - localPosition.z * scale.z - ); - - var worldChildPosition = joint.Transform.TransformPoint(localChildPosition); - var currentTail = spring.center != null - ? spring.center.InverseTransformPoint(worldChildPosition) - : worldChildPosition; - var parent = joint.Transform.parent; - blittableLogics.Add(new BlittableLogic - { - headTransformIndex = transformIndexDictionary[joint.Transform], - parentTransformIndex = parent != null ? transformIndexDictionary[parent] : -1, - currentTail = currentTail, - prevTail = currentTail, - localRotation = joint.DefaultLocalRotation, - boneAxis = localChildPosition.normalized, - length = localChildPosition.magnitude - }); - } - } - - Profiler.EndSample(); - - // 各種bufferの初期化 Profiler.BeginSample("FastSpringBone.ConstructBuffers.ConstructNativeArrays"); - 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); - Transforms = transforms.ToArray(); - Profiler.EndSample(); - + _externalData = new NativeArray(1, Allocator.Persistent); + _externalData[0] = new BlittableExternalData + { + ExternalForce = Vector3.zero, + IsSpringBoneEnabled = true, + }; + b.SetExternalDataPtr((BlittableExternalData*)_externalData.GetUnsafePtr()); + Springs = new NativeArray(b.BlittableSprings.ToArray(), Allocator.Persistent); + Joints = new NativeArray(b.BlittableJoints.ToArray(), Allocator.Persistent); + Colliders = new NativeArray(b.BlittableColliders.ToArray(), Allocator.Persistent); + Logics = new NativeArray(b.BlittableLogics.ToArray(), Allocator.Persistent); + BlittableTransforms = new NativeArray(b.Transforms.Length, Allocator.Persistent); + Transforms = b.Transforms; Profiler.EndSample(); } diff --git a/Assets/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBufferBuilder.cs b/Assets/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBufferBuilder.cs new file mode 100644 index 000000000..dc239064b --- /dev/null +++ b/Assets/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBufferBuilder.cs @@ -0,0 +1,143 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Profiling; +using UniVRM10.FastSpringBones.Blittables; + +namespace UniVRM10.FastSpringBones.System +{ + public class FastSpringBoneBufferBuilder + { + public readonly List BlittableSprings = new(); + public readonly List BlittableJoints = new(); + public readonly List BlittableColliders = new(); + public readonly List BlittableLogics = new(); + public readonly Transform[] Transforms; + + public FastSpringBoneBufferBuilder(IEnumerable springs, bool simulateLastBone = false) + { + Profiler.BeginSample("FastSpringBone.ConstructBuffers.BufferBuilder"); + 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); + } + Transforms = transformHashSet.ToArray(); + var transformIndexDictionary = Transforms.Select((trs, index) => (trs, index)) + .ToDictionary(tuple => tuple.trs, tuple => tuple.index); + + 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 = simulateLastBone ? spring.joints.Length : spring.joints.Length - 1, + }, + centerTransformIndex = spring.center ? transformIndexDictionary[spring.center] : -1, + }; + BlittableSprings.Add(blittableSpring); + + BlittableColliders.AddRange(spring.colliders.Select(collider => + { + var blittable = collider.Collider; + blittable.transformIndex = transformIndexDictionary[collider.Transform]; + return blittable; + })); + BlittableJoints.AddRange(spring.joints + .Take(simulateLastBone ? spring.joints.Length : spring.joints.Length - 1).Select(joint => + { + var blittable = joint.Joint; + return blittable; + })); + + for (var i = 0; i < (simulateLastBone ? spring.joints.Length : spring.joints.Length - 1); ++i) + { + var joint = spring.joints[i]; + var tailJoint = i + 1 < spring.joints.Length ? spring.joints[i + 1] : (FastSpringBoneJoint?)null; + var parentJoint = i - 1 >= 0 ? spring.joints[i - 1] : (FastSpringBoneJoint?)null; + var localPosition = Vector3.zero; + if (tailJoint.HasValue) + { + localPosition = tailJoint.Value.Transform.localPosition; + } + else + { + if (parentJoint.HasValue) + { + var delta = joint.Transform.position - parentJoint.Value.Transform.position; + localPosition = + joint.Transform.worldToLocalMatrix.MultiplyPoint(joint.Transform.position + delta); + } + else + { + localPosition = Vector3.down; + } + } + + var scale = tailJoint.HasValue ? tailJoint.Value.Transform.lossyScale : joint.Transform.lossyScale; + var localChildPosition = + new Vector3( + localPosition.x * scale.x, + localPosition.y * scale.y, + localPosition.z * scale.z + ); + + var worldChildPosition = joint.Transform.TransformPoint(localChildPosition); + var currentTail = spring.center != null + ? spring.center.InverseTransformPoint(worldChildPosition) + : worldChildPosition; + var parent = joint.Transform.parent; + BlittableLogics.Add(new BlittableLogic + { + headTransformIndex = transformIndexDictionary[joint.Transform], + parentTransformIndex = parent != null ? transformIndexDictionary[parent] : -1, + currentTail = currentTail, + prevTail = currentTail, + localRotation = joint.DefaultLocalRotation, + boneAxis = localChildPosition.normalized, + length = localChildPosition.magnitude + }); + } + } + Profiler.EndSample(); + } + + public unsafe void SetExternalDataPtr(BlittableExternalData* externalData) + { + for (int i = 0; i < BlittableSprings.Count; ++i) + { + // blittableSprings[i] = blittableSprings[i] with + // { + // ExternalData = externalData, + // }; + var b = BlittableSprings[i]; + BlittableSprings[i] = new BlittableSpring + { + centerTransformIndex = b.centerTransformIndex, + colliderSpan = b.colliderSpan, + logicSpan = b.logicSpan, + transformIndexOffset = b.transformIndexOffset, + ExternalData = externalData, + }; + } + } + } +} \ No newline at end of file diff --git a/Assets/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBufferBuilder.cs.meta b/Assets/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBufferBuilder.cs.meta new file mode 100644 index 000000000..29bea2967 --- /dev/null +++ b/Assets/VRM10/Runtime/FastSpringBone/InputPorts/FastSpringBoneBufferBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82dbc85cfa7168546b209a51f6342d84 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: