From da81c27b8130879e0119c4b8ceed792a6db09a4d Mon Sep 17 00:00:00 2001 From: notargs Date: Wed, 29 Sep 2021 16:11:34 +0900 Subject: [PATCH 1/6] Add FastSpringBone --- Assets/VRM/Runtime/FastSpringBone.meta | 8 + .../Runtime/FastSpringBone/Blittables.meta | 8 + .../Blittables/BlittableCollider.cs | 20 +++ .../Blittables/BlittableCollider.cs.meta | 3 + .../Blittables/BlittableColliderGroup.cs | 20 +++ .../Blittables/BlittableColliderGroup.cs.meta | 3 + .../Blittables/BlittableColliderGroups.cs | 34 ++++ .../BlittableColliderGroups.cs.meta | 3 + .../Blittables/BlittableColliders.cs | 19 +++ .../Blittables/BlittableColliders.cs.meta | 3 + .../Blittables/BlittablePoint.cs | 149 ++++++++++++++++++ .../Blittables/BlittablePoint.cs.meta | 3 + .../Blittables/BlittablePoints.cs | 23 +++ .../Blittables/BlittablePoints.cs.meta | 3 + .../Blittables/BlittableRootBone.cs | 64 ++++++++ .../Blittables/BlittableRootBone.cs.meta | 3 + .../Blittables/BlittableTransform.cs | 72 +++++++++ .../Blittables/BlittableTransform.cs.meta | 3 + .../Runtime/FastSpringBone/Components.meta | 8 + .../Components/FastSpringBoneColliderGroup.cs | 31 ++++ .../FastSpringBoneColliderGroup.cs.meta | 3 + .../Components/FastSpringBoneScheduler.cs | 100 ++++++++++++ .../FastSpringBoneScheduler.cs.meta | 3 + .../Components/FastSpringRootBone.cs | 124 +++++++++++++++ .../Components/FastSpringRootBone.cs.meta | 3 + .../FastSpringBone/FastSpringBone.asmdef | 21 +++ .../FastSpringBone/FastSpringBone.asmdef.meta | 7 + .../FastSpringBone/NativeWrappers.meta | 8 + .../NativeWrappers/NativeColliderGroup.cs | 31 ++++ .../NativeColliderGroup.cs.meta | 3 + .../NativeWrappers/NativeColliderGroups.cs | 78 +++++++++ .../NativeColliderGroups.cs.meta | 3 + .../NativeWrappers/NativePointer.cs | 35 ++++ .../NativeWrappers/NativePointer.cs.meta | 3 + .../NativeWrappers/NativePoints.cs | 39 +++++ .../NativeWrappers/NativePoints.cs.meta | 3 + .../NativeWrappers/NativeTransform.cs | 43 +++++ .../NativeWrappers/NativeTransform.cs.meta | 3 + .../Runtime/FastSpringBone/Registries.meta | 8 + .../Registries/ColliderGroupRegistry.cs | 8 + .../Registries/ColliderGroupRegistry.cs.meta | 3 + .../FastSpringBone/Registries/Registry.cs | 28 ++++ .../Registries/Registry.cs.meta | 3 + .../Registries/RootBoneRegistry.cs | 12 ++ .../Registries/RootBoneRegistry.cs.meta | 3 + .../Registries/TransformRegistry.cs | 60 +++++++ .../Registries/TransformRegistry.cs.meta | 3 + .../TransformSynchronizationType.cs | 8 + .../TransformSynchronizationType.cs.meta | 3 + .../Runtime/FastSpringBone/Schedulers.meta | 8 + .../Schedulers/PullTransformJobScheduler.cs | 119 ++++++++++++++ .../PullTransformJobScheduler.cs.meta | 3 + .../Schedulers/PushTransformJobScheduler.cs | 119 ++++++++++++++ .../PushTransformJobScheduler.cs.meta | 3 + .../UpdateSpringBoneJobScheduler.cs | 113 +++++++++++++ .../UpdateSpringBoneJobScheduler.cs.meta | 3 + 56 files changed, 1497 insertions(+) create mode 100644 Assets/VRM/Runtime/FastSpringBone.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableCollider.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableCollider.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroup.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroup.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroups.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroups.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliders.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliders.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoint.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoint.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoints.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoints.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableRootBone.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableRootBone.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableTransform.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableTransform.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Components.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneColliderGroup.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneColliderGroup.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneScheduler.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneScheduler.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Components/FastSpringRootBone.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Components/FastSpringRootBone.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/FastSpringBone.asmdef create mode 100644 Assets/VRM/Runtime/FastSpringBone/FastSpringBone.asmdef.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/NativeWrappers.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroup.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroup.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroups.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroups.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePointer.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePointer.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePoints.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePoints.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeTransform.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeTransform.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Registries.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Registries/ColliderGroupRegistry.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Registries/ColliderGroupRegistry.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Registries/Registry.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Registries/Registry.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Registries/RootBoneRegistry.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Registries/RootBoneRegistry.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Registries/TransformRegistry.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Registries/TransformRegistry.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Registries/TransformSynchronizationType.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Registries/TransformSynchronizationType.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Schedulers.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Schedulers/PullTransformJobScheduler.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Schedulers/PullTransformJobScheduler.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Schedulers/PushTransformJobScheduler.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Schedulers/PushTransformJobScheduler.cs.meta create mode 100644 Assets/VRM/Runtime/FastSpringBone/Schedulers/UpdateSpringBoneJobScheduler.cs create mode 100644 Assets/VRM/Runtime/FastSpringBone/Schedulers/UpdateSpringBoneJobScheduler.cs.meta diff --git a/Assets/VRM/Runtime/FastSpringBone.meta b/Assets/VRM/Runtime/FastSpringBone.meta new file mode 100644 index 000000000..cf175ab02 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cf09adfffebbff24eb2185e1d9b5b0a9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables.meta b/Assets/VRM/Runtime/FastSpringBone/Blittables.meta new file mode 100644 index 000000000..f41a4746d --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b2c4f2f05fcb4fb49be96d3b99236983 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableCollider.cs b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableCollider.cs new file mode 100644 index 000000000..351806a00 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableCollider.cs @@ -0,0 +1,20 @@ +using UnityEngine; + +namespace VRM.FastSpringBones.Blittables +{ + /// + /// VRMSpringBoneのSphereColliderをBlittableにしたもの + /// 位置情報は親であるColliderGroupが持つ + /// + public readonly struct BlittableCollider + { + public Vector3 Offset { get; } + public float Radius { get; } + + public BlittableCollider(Vector3 offset, float radius) + { + Offset = offset; + Radius = radius; + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableCollider.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableCollider.cs.meta new file mode 100644 index 000000000..be5b7aec3 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableCollider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cc94117758e24aca9cf44d3f930fdcb0 +timeCreated: 1550209189 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroup.cs b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroup.cs new file mode 100644 index 000000000..a53c1ab79 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroup.cs @@ -0,0 +1,20 @@ +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; + +namespace VRM.FastSpringBones.Blittables +{ + /// + /// VRMSpringBoneのColliderGroupをBlittableにしたもの + /// + public readonly struct BlittableColliderGroup + { + public BlittableColliders Colliders { get; } + public unsafe BlittableTransform* Transform { get; } + + public unsafe BlittableColliderGroup(NativeArray colliders, BlittableTransform* transform) + { + Colliders = new BlittableColliders((BlittableCollider*)colliders.GetUnsafePtr(), colliders.Length); + Transform = transform; + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroup.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroup.cs.meta new file mode 100644 index 000000000..64eb463ac --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroup.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9bceae7ad8eb4021912778484d1b2ebc +timeCreated: 1550223602 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroups.cs b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroups.cs new file mode 100644 index 000000000..e8eb037bc --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroups.cs @@ -0,0 +1,34 @@ +using UnityEngine; + +namespace VRM.FastSpringBones.Blittables +{ + /// + /// BlittableColliderGroupのポインタの配列 + /// + public readonly unsafe struct BlittableColliderGroups + { + private readonly BlittableColliderGroup* _data; + public int Length { get; } + + public BlittableColliderGroup this[int i] => _data[i]; + + public void DrawGizmos() + { + for (var i = 0; i < Length; i++) + { + var group = this[i]; + var colliders = group.Colliders; + for (var j = 0; j < colliders.Count; ++j) + { + Gizmos.DrawWireSphere(group.Transform->WorldPosition, colliders[j].Radius); + } + } + } + + public BlittableColliderGroups(BlittableColliderGroup* data, int length) + { + _data = data; + Length = length; + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroups.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroups.cs.meta new file mode 100644 index 000000000..4c768f0d9 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliderGroups.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 61f56040664345a8aba5309e7714f8f2 +timeCreated: 1550563011 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliders.cs b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliders.cs new file mode 100644 index 000000000..adbc4d739 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliders.cs @@ -0,0 +1,19 @@ +namespace VRM.FastSpringBones.Blittables +{ + /// + /// BlittableColliderのポインタの配列 + /// + public unsafe struct BlittableColliders + { + private readonly BlittableCollider* _colliders; + public int Count { get; } + + public BlittableCollider this[int i] => _colliders[i]; + + public BlittableColliders(BlittableCollider* colliders, int count) + { + _colliders = colliders; + Count = count; + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliders.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliders.cs.meta new file mode 100644 index 000000000..b93aac749 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableColliders.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 07087baebec34286ac230d58cd0163d2 +timeCreated: 1550562383 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoint.cs b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoint.cs new file mode 100644 index 000000000..f508200c8 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoint.cs @@ -0,0 +1,149 @@ +using UnityEngine; + +namespace VRM.FastSpringBones.Blittables +{ + /// + /// VRMSpringBoneLogicをBlittableにしたもの + /// ベルレ積分など、コアな計算を行う + /// + public unsafe struct BlittablePoint + { + private readonly float _length; + private readonly Quaternion _localRotation; + private readonly Vector3 _boneAxis; + private readonly float _radius; + private Vector3 _prevPosition; + + private readonly BlittableColliderGroups* _blittableColliderGroups; + private readonly BlittableTransform* _center; + + public Vector3 CurrentPosition { get; private set; } + + private readonly BlittableTransform* _transform; + + public BlittablePoint( + Transform transform, + float radius, + BlittableTransform* center, + BlittableColliderGroups* blittableColliderGroups, + BlittableTransform* blittableTransform) + { + Vector3 localPosition; + if (transform.childCount == 0) + { + var delta = transform.position - transform.parent.position; + var childPosition = transform.position + delta.normalized * 0.07f; + localPosition = transform.worldToLocalMatrix.MultiplyPoint(childPosition); + } + else + { + var firstChild = transform.GetChild(0); + var scale = firstChild.lossyScale; + localPosition = firstChild.localPosition; + localPosition.x *= scale.x; + localPosition.y *= scale.y; + localPosition.z *= scale.z; + } + + var worldChildPosition = (Vector3)transform.TransformPoint(localPosition); + _prevPosition = CurrentPosition = center != null ? center->LocalToWorld.inverse.MultiplyPoint3x4(worldChildPosition) : worldChildPosition; + + _localRotation = transform.localRotation; + _boneAxis = localPosition.normalized; + _length = localPosition.magnitude; + _radius = radius; + _blittableColliderGroups = blittableColliderGroups; + _transform = blittableTransform; + _center = center; + } + + public void Update(float stiffnessForce, float dragForce, Vector3 external) + { + // 親のRotationが変わっている可能性があるので更新する + _transform->UpdateLocalToWorldMatrix(); + + Vector3 currentPosition; + Vector3 prevPosition; + + if (_center == null) + { + currentPosition = CurrentPosition; + prevPosition = _prevPosition; + } + else + { + var centerLocalToWorld = _center->LocalToWorld; + currentPosition = centerLocalToWorld.MultiplyPoint3x4(CurrentPosition); + prevPosition = centerLocalToWorld.MultiplyPoint3x4(_prevPosition); + } + + // verlet積分で次の位置を計算 + var nextPosition = currentPosition + + (currentPosition - prevPosition) * (1.0f - dragForce) // 前フレームの移動を継続する(減衰もあるよ) + + _transform->ParentWorldRotation * _localRotation * _boneAxis * stiffnessForce // 親の回転による子ボーンの移動目標 + + external; // 外力による移動量 + + // 長さをboneLengthに強制 + var position = _transform->WorldPosition; + nextPosition = position + (nextPosition - position).normalized * _length; + + nextPosition = Collision(nextPosition, position); + + if (_center == null) + { + _prevPosition = currentPosition; + CurrentPosition = nextPosition; + } + else + { + var centerWorldToLocal = _center->LocalToWorld.inverse; + _prevPosition = centerWorldToLocal.MultiplyPoint3x4(currentPosition); + CurrentPosition = centerWorldToLocal.MultiplyPoint3x4(nextPosition); + } + + //回転を適用 + _transform->SetWorldRotation(ApplyRotation(nextPosition)); + } + + private Vector3 Collision(Vector3 nextPosition, Vector3 position) + { + for (var i = 0; i < _blittableColliderGroups->Length; ++i) + { + var colliderGroup = (*_blittableColliderGroups)[i]; + + for (var j = 0; j < colliderGroup.Colliders.Count; ++j) + { + var collider = colliderGroup.Colliders[j]; + var colliderPosition = colliderGroup.Transform->TransformPoint(collider.Offset); + var r = _radius + collider.Radius; + + if (!((nextPosition - colliderPosition).sqrMagnitude <= (r * r))) continue; + + // ヒット。Colliderの半径方向に押し出す + var normal = (nextPosition - colliderPosition).normalized; + var posFromCollider = colliderPosition + normal * (_radius + collider.Radius); + + // 長さをboneLengthに強制 + nextPosition = position + (posFromCollider - position).normalized * _length; + } + } + return nextPosition; + } + + private static Quaternion FromToRotation(Vector3 from, Vector3 to) + => Quaternion.AxisAngle( + angle: Mathf.Acos(Mathf.Clamp(Vector3.Dot(from.normalized, to.normalized), -1f, 1f)), + axis: Vector3.Cross(from, to).normalized + ); + + private Quaternion ApplyRotation(Vector3 nextTail) + { + var rotation = _transform->ParentWorldRotation * _localRotation; + return + FromToRotation( + rotation * _boneAxis, + nextTail - _transform->WorldPosition) * + rotation; + } + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoint.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoint.cs.meta new file mode 100644 index 000000000..2e93186cc --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoint.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f3f0fc54e34944c892cec2b1e86de7d7 +timeCreated: 1549430605 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoints.cs b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoints.cs new file mode 100644 index 000000000..8a91baf39 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoints.cs @@ -0,0 +1,23 @@ +namespace VRM.FastSpringBones.Blittables +{ + /// + /// BlittablePointのポインタの配列 + /// + public unsafe struct BlittablePoints + { + private readonly BlittablePoint* _points; + public int Count { get; } + + public BlittablePoint this[int i] + { + get => _points[i]; + set => _points[i] = value; + } + + public BlittablePoints(BlittablePoint* points, int count) + { + _points = points; + Count = count; + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoints.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoints.cs.meta new file mode 100644 index 000000000..a2653992c --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittablePoints.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0c39cdb389d141bbb084030dd8ebfe8b +timeCreated: 1550721598 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableRootBone.cs b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableRootBone.cs new file mode 100644 index 000000000..81753210d --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableRootBone.cs @@ -0,0 +1,64 @@ +using UnityEngine; + +namespace VRM.FastSpringBones.Blittables +{ + /// + /// 1本の毛束を示すBlittable型 + /// + public unsafe readonly struct BlittableRootBone + { + private readonly float _gravityPower; + private readonly Vector3 _gravityDir; + private readonly float _dragForce; + private readonly float _stiffnessForce; + private readonly BlittablePoints* _blittablePoints; + + public void DrawGizmos() + { + for (var i = 0; i < _blittablePoints->Count; i++) + { + var point = (*_blittablePoints)[i]; + Gizmos.DrawWireSphere(point.CurrentPosition, 0.05f); + } + for (var i = 0; i < _blittablePoints->Count - 1; i++) + { + var point1 = (*_blittablePoints)[i]; + var point2 = (*_blittablePoints)[i + 1]; + Gizmos.DrawLine(point1.CurrentPosition, point2.CurrentPosition); + } + } + + public BlittableRootBone( + float gravityPower, + Vector3 gravityDir, + float dragForce, + float stiffnessForce, + BlittablePoints* blittablePoints) + { + _gravityPower = gravityPower; + _gravityDir = gravityDir; + _dragForce = dragForce; + _stiffnessForce = stiffnessForce; + _blittablePoints = blittablePoints; + } + + public void Update(float deltaTime) + { + var stiffness = _stiffnessForce * deltaTime; + var external = _gravityDir * (_gravityPower * deltaTime); + for (var i = 0; i < _blittablePoints->Count; i++) + { + var point = (*_blittablePoints)[i]; + + // Pointを更新 + point.Update( + stiffness, + _dragForce, + external + ); + + (*_blittablePoints)[i] = point; + } + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableRootBone.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableRootBone.cs.meta new file mode 100644 index 000000000..dbba64284 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableRootBone.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bc470487e0a546f087709dbab3c7a6f1 +timeCreated: 1549952425 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableTransform.cs b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableTransform.cs new file mode 100644 index 000000000..b2e4f9947 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableTransform.cs @@ -0,0 +1,72 @@ +using UnityEngine; +using UnityEngine.Jobs; + +namespace VRM.FastSpringBones.Blittables +{ + /// + /// Transformの必要な機能だけを絞り、Blittableに対応させたクラス + /// + public unsafe struct BlittableTransform + { + private readonly BlittableTransform* _parent; + private Quaternion _worldRotation; + private Vector3 _localPosition; + private Vector3 _localScale; + private Quaternion _localRotation; + private Matrix4x4 _localToWorld; + + public Vector3 WorldPosition { get; private set; } + + public void SetWorldRotation(Quaternion rotation) + { + var parentWorldRotation = ParentWorldRotation; + _localRotation = Quaternion.Inverse(parentWorldRotation) * rotation; + UpdateLocalToWorldMatrix(); + } + + public Matrix4x4 LocalToWorld => _localToWorld; + + private Matrix4x4 LocalTransform => Matrix4x4.TRS(_localPosition, _localRotation, _localScale); + + public Quaternion ParentWorldRotation => _parent != null ? _parent->_worldRotation : Quaternion.identity; + + public BlittableTransform(BlittableTransform* parent, Transform transform) + { + _parent = parent; + + WorldPosition = transform.position; + _worldRotation = transform.rotation; + _localPosition = transform.localPosition; + _localRotation = transform.localRotation; + _localScale = transform.localScale; + + _localToWorld = transform.localToWorldMatrix; + } + + public void PullFrom(TransformAccess transform) + { + WorldPosition = transform.position; + _worldRotation = transform.rotation; + _localPosition = transform.localPosition; + _localRotation = transform.localRotation; + _localScale = transform.localScale; + + _localToWorld = transform.localToWorldMatrix; + } + + public void PushTo(TransformAccess transform) + { + transform.localPosition = _localPosition; + transform.localRotation = _localRotation; + } + + public Vector3 TransformPoint(Vector3 offset) => _localToWorld.MultiplyPoint3x4(offset); + + public void UpdateLocalToWorldMatrix() + { + _localToWorld = _parent == null ? LocalTransform : _parent->_localToWorld * LocalTransform; + WorldPosition = _localToWorld.MultiplyPoint3x4(Vector3.zero); + _worldRotation = _localToWorld.rotation; + } + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableTransform.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableTransform.cs.meta new file mode 100644 index 000000000..e5f912161 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Blittables/BlittableTransform.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bffbbf422e984d028cd82c11f2ca00b1 +timeCreated: 1550544819 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Components.meta b/Assets/VRM/Runtime/FastSpringBone/Components.meta new file mode 100644 index 000000000..8560bc54d --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Components.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 89d63c6c8787b9a4c80df0fb18aa3d43 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneColliderGroup.cs b/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneColliderGroup.cs new file mode 100644 index 000000000..b5fe7be3b --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneColliderGroup.cs @@ -0,0 +1,31 @@ +using UnityEngine; +using VRM.FastSpringBones.Blittables; +using VRM.FastSpringBones.NativeWrappers; +using VRM.FastSpringBones.Registries; + +namespace VRM.FastSpringBones.Components +{ + /// + /// VRMSpringBoneColliderGroupに対応したクラス + /// バッファの作成も行う + /// + public sealed unsafe class FastSpringBoneColliderGroup : MonoBehaviour + { + private NativeTransform _nativeTransform; + private NativeColliderGroup _nativeColliderGroup; + + public BlittableColliderGroup* ColliderGroupPtr => _nativeColliderGroup.GetUnsafePtr(); + + public void Initialize(TransformRegistry transformRegistry, BlittableCollider[] colliders) + { + _nativeTransform = new NativeTransform(transformRegistry, TransformSynchronizationType.PullOnly, transform); + _nativeColliderGroup = new NativeColliderGroup(colliders, _nativeTransform); + } + + private void OnDestroy() + { + _nativeTransform?.Dispose(); + _nativeColliderGroup?.Dispose(); + } + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneColliderGroup.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneColliderGroup.cs.meta new file mode 100644 index 000000000..ef47a8fc6 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneColliderGroup.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2c6ab135b4b945ee9d75c5476ea6bcc0 +timeCreated: 1550213674 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneScheduler.cs b/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneScheduler.cs new file mode 100644 index 000000000..fc125b062 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneScheduler.cs @@ -0,0 +1,100 @@ +using Unity.Jobs; +using UnityEngine; +using UnityEngine.Profiling; +using VRM.FastSpringBones.Registries; +using VRM.FastSpringBones.Schedulers; + +namespace VRM.FastSpringBones.Components +{ + /// + /// Jobを連続して発火させるComponent + /// シーンに1つだけあればいい + /// + [DefaultExecutionOrder(11000)] + public sealed class FastSpringBoneScheduler : MonoBehaviour + { + [SerializeField] private bool showGizmos; + + private CustomSampler _updateSampler; + + private PullTransformJobScheduler _pullTransformJobScheduler; + private PushTransformJobScheduler _pushTransformJobScheduler; + private UpdateSpringBoneJobScheduler _updateSpringBoneJobScheduler; + + private RootBoneRegistry _rootBoneRegistry; + private ColliderGroupRegistry _colliderGroupRegistry; + + private JobHandle _prevJobHandle; + + public bool ShowGizmos { get => showGizmos; set => showGizmos = value; } + + public void Initialize( + RootBoneRegistry rootBoneRegistry, + TransformRegistry transformRegistry, + ColliderGroupRegistry colliderGroupRegistry) + { + _rootBoneRegistry = rootBoneRegistry; + _colliderGroupRegistry = colliderGroupRegistry; + + _updateSampler = CustomSampler.Create("FastSpringBone(Update)"); + + _pullTransformJobScheduler = new PullTransformJobScheduler(transformRegistry); + _pushTransformJobScheduler = new PushTransformJobScheduler(transformRegistry); + _updateSpringBoneJobScheduler = new UpdateSpringBoneJobScheduler(_rootBoneRegistry); + + _rootBoneRegistry.SubscribeOnValueChanged(OnRootBoneChanged); + } + + private void OnDestroy() + { + _rootBoneRegistry.UnSubscribeOnValueChanged(OnRootBoneChanged); + _prevJobHandle.Complete(); + + _pullTransformJobScheduler.Dispose(); + _pushTransformJobScheduler.Dispose(); + _updateSpringBoneJobScheduler.Dispose(); + } + + private void OnRootBoneChanged() + { + _prevJobHandle.Complete(); + } + +#if UNITY_EDITOR + private void OnDrawGizmos() + { + if (!ShowGizmos) return; + + _prevJobHandle.Complete(); + + Gizmos.color = Color.blue; + foreach (var rootBoneWrapper in _rootBoneRegistry.Items) + { + rootBoneWrapper.Value.DrawGizmos(); + } + + Gizmos.color = Color.yellow; + foreach (var colliderGroup in _colliderGroupRegistry.Items) + { + colliderGroup.DrawGizmos(); + } + } +#endif + + private void LateUpdate() + { + _updateSampler.Begin(); + + _prevJobHandle.Complete(); + + var tempJobHandle = default(JobHandle); + tempJobHandle = _pullTransformJobScheduler.Schedule(tempJobHandle); + tempJobHandle = _updateSpringBoneJobScheduler.Schedule(tempJobHandle); + tempJobHandle = _pushTransformJobScheduler.Schedule(tempJobHandle); + + _prevJobHandle = tempJobHandle; + + _updateSampler.End(); + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneScheduler.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneScheduler.cs.meta new file mode 100644 index 000000000..bea119324 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringBoneScheduler.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2ea019701873487a8533c05f0daa1b37 +timeCreated: 1549521562 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringRootBone.cs b/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringRootBone.cs new file mode 100644 index 000000000..a6ec42ece --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringRootBone.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using VRM.FastSpringBones.Blittables; +using VRM.FastSpringBones.NativeWrappers; +using VRM.FastSpringBones.Registries; + +namespace VRM.FastSpringBones.Components +{ + /// + /// SpringBoneの1本の毛束の処理を担当するクラス + /// + public sealed class FastSpringRootBone : IDisposable + { + private readonly TransformRegistry _transformRegistry; + private readonly RootBoneRegistry _rootBoneRegistry; + private readonly ColliderGroupRegistry _colliderGroupRegistry; + private readonly Transform _transform; + + private float _radius; + private NativeTransform _center; + + private IReadOnlyDictionary _transformIndexMap; + private NativeColliderGroups _nativeColliderGroups; + + private NativePoints _nativePoints; + private NativePointer _rootBoneWrapper; + + private readonly IList _transformWrappers = new List(); + private readonly IList> _points = new List>(); + + public FastSpringRootBone( + TransformRegistry transformRegistry, + Transform transform, + RootBoneRegistry rootBoneRegistry, + ColliderGroupRegistry colliderGroupRegistry + ) + { + _transformRegistry = transformRegistry; + _transform = transform; + _rootBoneRegistry = rootBoneRegistry; + _colliderGroupRegistry = colliderGroupRegistry; + } + + public IReadOnlyList ColliderGroups + { + get => _nativeColliderGroups.ColliderGroups; + set => _nativeColliderGroups.ColliderGroups = value; + } + + public unsafe void Initialize( + float gravityPower, + Vector3 gravityDir, + float dragForce, + float stiffnessForce, + IReadOnlyList colliderGroups, + float radius, + Transform center) + { + _radius = radius; + if (center != null) + { + _center = new NativeTransform(_transformRegistry, TransformSynchronizationType.PullOnly, center); + } + + _nativeColliderGroups = new NativeColliderGroups(colliderGroups); + + NativeTransform parent = null; + if (_transform.parent) + { + parent = new NativeTransform(_transformRegistry, TransformSynchronizationType.PullOnly, _transform.parent); + } + SetupRecursive(_transform, parent); + + _nativePoints = new NativePoints(_points); + + _rootBoneWrapper = new NativePointer(new BlittableRootBone(gravityPower, gravityDir, dragForce, stiffnessForce, _nativePoints.GetUnsafePtr())); + _rootBoneRegistry.Register(_rootBoneWrapper); + _colliderGroupRegistry.Register(_nativeColliderGroups); + } + + public void Dispose() + { + _colliderGroupRegistry.Unregister(_nativeColliderGroups); + _rootBoneRegistry.Unregister(_rootBoneWrapper); + + foreach (var transformWrapper in _transformWrappers) + { + transformWrapper.Dispose(); + } + + foreach (var point in _points) + { + point.Dispose(); + } + + _center?.Dispose(); + _nativeColliderGroups?.Dispose(); + _nativePoints.Dispose(); + _rootBoneWrapper.Dispose(); + } + + private unsafe void SetupRecursive(Transform trs, NativeTransform parent = null) + { + var transformWrapper = new NativeTransform(_transformRegistry, TransformSynchronizationType.PushOnly, trs, parent); + _transformWrappers.Add(transformWrapper); + + var point = new NativePointer( + new BlittablePoint( + trs, + _radius, + _center != null ? _center.GetUnsafePtr() : null, + _nativeColliderGroups.GetUnsafePtr(), + transformWrapper.GetUnsafePtr()) + ); + _points.Add(point); + + for (var i = 0; i < trs.childCount; ++i) + { + SetupRecursive(trs.GetChild(i), transformWrapper); + } + } + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringRootBone.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringRootBone.cs.meta new file mode 100644 index 000000000..6f9dcd2fe --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Components/FastSpringRootBone.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 24cdd60af2d54c908e84b17802bfb5bc +timeCreated: 1550036996 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/FastSpringBone.asmdef b/Assets/VRM/Runtime/FastSpringBone/FastSpringBone.asmdef new file mode 100644 index 000000000..43d6fca9b --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/FastSpringBone.asmdef @@ -0,0 +1,21 @@ +{ + "name": "FastSpringBone", + "references": [ + "GUID:2665a8d13d1b3f18800f46e256720795" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.unity.burst", + "expression": "0.0.1", + "define": "ENABLE_SPRINGBONE_BURST" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/FastSpringBone.asmdef.meta b/Assets/VRM/Runtime/FastSpringBone/FastSpringBone.asmdef.meta new file mode 100644 index 000000000..c086fa0df --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/FastSpringBone.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ac229b552c3025545b074203f857547c +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers.meta b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers.meta new file mode 100644 index 000000000..c09ce17be --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 96634b0bb2d12d044a21f3fdff7a2c43 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroup.cs b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroup.cs new file mode 100644 index 000000000..821d7acc7 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroup.cs @@ -0,0 +1,31 @@ +using System; +using Unity.Collections; +using VRM.FastSpringBones.Blittables; + +namespace VRM.FastSpringBones.NativeWrappers +{ + /// + /// BlittableColliderGroupのライフサイクルを管理するWrapper + /// + public sealed unsafe class NativeColliderGroup : IDisposable + { + private readonly NativePointer _nativePointer; + + private NativeArray Colliders { get; } + + public BlittableColliderGroup* GetUnsafePtr() => _nativePointer.GetUnsafePtr(); + + public NativeColliderGroup(BlittableCollider[] colliders, NativeTransform nativeTransform) + { + Colliders = new NativeArray(colliders, Allocator.Persistent); + _nativePointer = new NativePointer(new BlittableColliderGroup(Colliders, nativeTransform.GetUnsafePtr())); + } + + public void Dispose() + { + if (Colliders.IsCreated) Colliders.Dispose(); + + _nativePointer.Dispose(); + } + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroup.cs.meta b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroup.cs.meta new file mode 100644 index 000000000..64eae28a2 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroup.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4cf2baba01384c31a1fdcca7489007f4 +timeCreated: 1550640666 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroups.cs b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroups.cs new file mode 100644 index 000000000..d3d75e220 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroups.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using VRM.FastSpringBones.Blittables; +using VRM.FastSpringBones.Components; + +namespace VRM.FastSpringBones.NativeWrappers +{ + /// + /// BlittableColliderGroupsのライフサイクルを管理するWrapper + /// + public sealed unsafe class NativeColliderGroups : IDisposable + { + private readonly NativePointer _nativePointer = new NativePointer(); + private NativeArray _colliderGroupArray; + private IReadOnlyList _colliderGroups; + + //FIXME: Disposeされた後にUpdateColliderGroupsが呼ばれるのをとりあえず防ぐためのフラグ + private bool _isDisposed = false; + + public BlittableColliderGroups* GetUnsafePtr() => _nativePointer.GetUnsafePtr(); + public void DrawGizmos() => _nativePointer.Value.DrawGizmos(); + + public IReadOnlyList ColliderGroups + { + get => _colliderGroups; + set + { + _colliderGroups = value; + UpdateColliderGroups(); + } + } + + private void UpdateColliderGroups() + { + if (_isDisposed) return; + if (_colliderGroupArray.IsCreated) + { + _colliderGroupArray.Dispose(); + } + CreateColliderGroupArray(_colliderGroups); + UpdateData(); + } + + public NativeColliderGroups(IReadOnlyList colliderGroups) + { + _colliderGroups = colliderGroups; + UpdateColliderGroups(); + } + + public void Dispose() + { + if (_colliderGroupArray.IsCreated) + { + _colliderGroupArray.Dispose(); + _isDisposed = true; + } + _nativePointer.Dispose(); + } + + private void CreateColliderGroupArray(IReadOnlyList colliderGroups) + { + _colliderGroupArray = new NativeArray(colliderGroups.Count, Allocator.Persistent); + for (var i = 0; i < _colliderGroupArray.Length; ++i) + { + _colliderGroupArray[i] = *colliderGroups[i].ColliderGroupPtr; + } + } + + private void UpdateData() + { + _nativePointer.Value = new BlittableColliderGroups( + (BlittableColliderGroup*)_colliderGroupArray.GetUnsafePtr(), + _colliderGroupArray.Length); + } + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroups.cs.meta b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroups.cs.meta new file mode 100644 index 000000000..e70ff2e4e --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroups.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3944dc9ee4a94814bc1d333fd0b7ba82 +timeCreated: 1550645184 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePointer.cs b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePointer.cs new file mode 100644 index 000000000..cc42524d7 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePointer.cs @@ -0,0 +1,35 @@ +using System; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; + +namespace VRM.FastSpringBones.NativeWrappers +{ + public sealed class NativePointer : IDisposable where T : unmanaged + { + private readonly unsafe T* _unsafePtr; + + public unsafe T* GetUnsafePtr() => _unsafePtr; + + public unsafe T Value + { + get => *_unsafePtr; + set => *_unsafePtr = value; + } + + public unsafe NativePointer() + { + _unsafePtr = (T*)UnsafeUtility.Malloc(sizeof(T), 16, Allocator.Persistent); + } + + public unsafe NativePointer(T value) + { + _unsafePtr = (T*)UnsafeUtility.Malloc(sizeof(T), 16, Allocator.Persistent); + Value = value; + } + + public unsafe void Dispose() + { + UnsafeUtility.Free(_unsafePtr, Allocator.Persistent); + } + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePointer.cs.meta b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePointer.cs.meta new file mode 100644 index 000000000..2d48eac46 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePointer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 70f8b67ae2644eb999cfb45ea5bf25a3 +timeCreated: 1595316733 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePoints.cs b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePoints.cs new file mode 100644 index 000000000..f62b0baaf --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePoints.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using VRM.FastSpringBones.Blittables; + +namespace VRM.FastSpringBones.NativeWrappers +{ + /// + /// BlittablePointsGroupのライフサイクルを管理するWrapper + /// + public sealed unsafe class NativePoints : IDisposable + { + private readonly NativePointer _nativePointer; + private NativeArray _buffer; + + public BlittablePoints* GetUnsafePtr() => _nativePointer.GetUnsafePtr(); + + public NativePoints(IList> points) + { + _buffer = new NativeArray(points.Count, Allocator.Persistent); + for (var i = 0; i < _buffer.Length; ++i) + { + _buffer[i] = points[i].Value; + } + + _nativePointer = new NativePointer(new BlittablePoints((BlittablePoint*) _buffer.GetUnsafePtr(), _buffer.Length)); + } + + public void Dispose() + { + if (_buffer.IsCreated) + { + _buffer.Dispose(); + } + _nativePointer.Dispose(); + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePoints.cs.meta b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePoints.cs.meta new file mode 100644 index 000000000..0139520d7 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativePoints.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7a8763ad7e8243d3b4001a2beb37bf9d +timeCreated: 1550723674 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeTransform.cs b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeTransform.cs new file mode 100644 index 000000000..89c592c11 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeTransform.cs @@ -0,0 +1,43 @@ +using System; +using UnityEngine; +using VRM.FastSpringBones.Blittables; +using VRM.FastSpringBones.Registries; + +namespace VRM.FastSpringBones.NativeWrappers +{ + /// + /// BlittableTransformのライフサイクルを管理するWrapper + /// + public sealed class NativeTransform : IDisposable + { + private readonly NativePointer _nativePointer; + public Transform Transform { get; } + + private readonly TransformRegistry _transformRegistry; + + public unsafe BlittableTransform* GetUnsafePtr() => _nativePointer.GetUnsafePtr(); + public BlittableTransform Value => _nativePointer.Value; + + public unsafe NativeTransform( + TransformRegistry transformRegistry, + TransformSynchronizationType transformSynchronizationType, + Transform transform, + NativeTransform parent = null + ) + { + _nativePointer = new NativePointer(new BlittableTransform(parent != null ? parent.GetUnsafePtr() : null, transform)); + + Transform = transform; + + _transformRegistry = transformRegistry; + _transformRegistry.Register(this, transformSynchronizationType); + } + + public void Dispose() + { + _transformRegistry.Unregister(this); + + _nativePointer.Dispose(); + } + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeTransform.cs.meta b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeTransform.cs.meta new file mode 100644 index 000000000..b62050944 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeTransform.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2acc8862ffb44f4fbd4e1e03e9a9d46e +timeCreated: 1550545201 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Registries.meta b/Assets/VRM/Runtime/FastSpringBone/Registries.meta new file mode 100644 index 000000000..b148ee1f1 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Registries.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: daa8d50bee84b0c4387d22784cce66ff +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Runtime/FastSpringBone/Registries/ColliderGroupRegistry.cs b/Assets/VRM/Runtime/FastSpringBone/Registries/ColliderGroupRegistry.cs new file mode 100644 index 000000000..2af47cc47 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Registries/ColliderGroupRegistry.cs @@ -0,0 +1,8 @@ +using VRM.FastSpringBones.NativeWrappers; + +namespace VRM.FastSpringBones.Registries +{ + public sealed class ColliderGroupRegistry : Registry + { + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/Registries/ColliderGroupRegistry.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Registries/ColliderGroupRegistry.cs.meta new file mode 100644 index 000000000..5c1188773 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Registries/ColliderGroupRegistry.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: eec0fe3cd3694a379885fa62a9994bd5 +timeCreated: 1594963749 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Registries/Registry.cs b/Assets/VRM/Runtime/FastSpringBone/Registries/Registry.cs new file mode 100644 index 000000000..ce0209d49 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Registries/Registry.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; + +namespace VRM.FastSpringBones.Registries +{ + public class Registry + { + private readonly List _items = new List(); + private Action _onValueChanged; + + public IReadOnlyList Items => _items; + + public void Register(T value) + { + _items.Add(value); + _onValueChanged?.Invoke(); + } + + public void Unregister(T value) + { + _items.Remove(value); + _onValueChanged?.Invoke(); + } + + public void SubscribeOnValueChanged(Action action) => _onValueChanged += action; + public void UnSubscribeOnValueChanged(Action action) => _onValueChanged -= action; + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/Registries/Registry.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Registries/Registry.cs.meta new file mode 100644 index 000000000..5020d1e78 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Registries/Registry.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0d3b558d03dd42b184512fe19797ff07 +timeCreated: 1595407071 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Registries/RootBoneRegistry.cs b/Assets/VRM/Runtime/FastSpringBone/Registries/RootBoneRegistry.cs new file mode 100644 index 000000000..8da01d254 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Registries/RootBoneRegistry.cs @@ -0,0 +1,12 @@ +using VRM.FastSpringBones.Blittables; +using VRM.FastSpringBones.NativeWrappers; + +namespace VRM.FastSpringBones.Registries +{ + /// + /// 今生きているRootBoneの一覧を返すクラス + /// + public sealed class RootBoneRegistry : Registry> + { + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Registries/RootBoneRegistry.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Registries/RootBoneRegistry.cs.meta new file mode 100644 index 000000000..0d07dcafc --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Registries/RootBoneRegistry.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4609c8e2a4c64fb7b3bfa587f475e965 +timeCreated: 1550734399 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Registries/TransformRegistry.cs b/Assets/VRM/Runtime/FastSpringBone/Registries/TransformRegistry.cs new file mode 100644 index 000000000..05c956f2b --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Registries/TransformRegistry.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using VRM.FastSpringBones.NativeWrappers; + +namespace VRM.FastSpringBones.Registries +{ + /// + /// 今生きているTransformの一覧を返すクラス + /// + public sealed class TransformRegistry + { + private readonly List _transforms = new List(); + public IReadOnlyList Transforms => _transforms; + + private readonly List _pullTargets = new List(); + public IReadOnlyList PullTargets => _pullTargets; + + private readonly List _pushTargets = new List(); + public IReadOnlyList PushTargets => _pushTargets; + + private Action _onValueChanged; + + public void SubscribeOnValueChanged(Action action) => _onValueChanged += action; + + public void UnSubscribeOnValueChanged(Action action) => _onValueChanged -= action; + + public void Register(NativeTransform nativeTransform, TransformSynchronizationType synchronizationType) + { + _transforms.Add(nativeTransform); + switch (synchronizationType) + { + case TransformSynchronizationType.PullOnly: + _pullTargets.Add(nativeTransform); + break; + case TransformSynchronizationType.PushOnly: + _pushTargets.Add(nativeTransform); + break; + default: + throw new ArgumentOutOfRangeException(nameof(synchronizationType), synchronizationType, null); + } + _onValueChanged?.Invoke(); + } + + public void Unregister(NativeTransform nativeTransform) + { + _transforms.Remove(nativeTransform); + + if (_pullTargets.Contains(nativeTransform)) + { + _pullTargets.Remove(nativeTransform); + } + + if (_pushTargets.Contains(nativeTransform)) + { + _pushTargets.Remove(nativeTransform); + } + _onValueChanged?.Invoke(); + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Registries/TransformRegistry.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Registries/TransformRegistry.cs.meta new file mode 100644 index 000000000..d0c6267e8 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Registries/TransformRegistry.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 102dd7059fb34c00a7d1d6d4f2c38729 +timeCreated: 1550666913 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Registries/TransformSynchronizationType.cs b/Assets/VRM/Runtime/FastSpringBone/Registries/TransformSynchronizationType.cs new file mode 100644 index 000000000..bd5a34b87 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Registries/TransformSynchronizationType.cs @@ -0,0 +1,8 @@ +namespace VRM.FastSpringBones.Registries +{ + public enum TransformSynchronizationType + { + PullOnly, + PushOnly, + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Registries/TransformSynchronizationType.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Registries/TransformSynchronizationType.cs.meta new file mode 100644 index 000000000..c68e0bc18 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Registries/TransformSynchronizationType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6d3911eb7ee54861b51bccf4ed32aec2 +timeCreated: 1551169872 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Schedulers.meta b/Assets/VRM/Runtime/FastSpringBone/Schedulers.meta new file mode 100644 index 000000000..8165aee2d --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Schedulers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 802ad91bcfdacbd4bbce16eff061cd68 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Runtime/FastSpringBone/Schedulers/PullTransformJobScheduler.cs b/Assets/VRM/Runtime/FastSpringBone/Schedulers/PullTransformJobScheduler.cs new file mode 100644 index 000000000..600ac0d39 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Schedulers/PullTransformJobScheduler.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +#if ENABLE_SPRINGBONE_BURST +using Unity.Burst; +#endif +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Jobs; +using UnityEngine.Jobs; +using UnityEngine.Profiling; +using VRM.FastSpringBones.Blittables; +using VRM.FastSpringBones.NativeWrappers; +using VRM.FastSpringBones.Registries; + +namespace VRM.FastSpringBones.Schedulers +{ + /// + /// GameObjectの世界からBlittableな世界へTransformを複製する処理を行うクラス + /// + public sealed unsafe class PullTransformJobScheduler : IDisposable + { + private BlittableTransform** _transformPointers; + private TransformAccessArray _transformAccessArray; + + private readonly CustomSampler _sampler = CustomSampler.Create("Schedule CopyFromTransformJob"); + private readonly TransformRegistry _transformRegistry; + + private bool _dirty = true; + + private IReadOnlyList Targets => _transformRegistry.PullTargets; + + public PullTransformJobScheduler(TransformRegistry transformRegistry) + { + _transformRegistry = transformRegistry; + + _transformRegistry.SubscribeOnValueChanged(OnTransformChanged); + } + + private void OnTransformChanged() + { + _dirty = true; + } + + public JobHandle Schedule(JobHandle dependOn = default(JobHandle)) + { + if (Targets.Count == 0) + { + return dependOn; + } + + _sampler.Begin(); + + // リストが変更されていたらバッファを再構築 + if (_dirty) + { + ReconstructBuffers(); + + _dirty = false; + } + + // ジョブを発火 + var job = new Job { TransformPointers = _transformPointers }; + var jobHandle = job.Schedule(_transformAccessArray, dependOn); + + _sampler.End(); + + return jobHandle; + } + + private void ReconstructBuffers() + { + ReleaseBuffers(); + + var transforms = Targets; + _transformPointers = (BlittableTransform**)UnsafeUtility.Malloc( + sizeof(BlittableTransform*) * transforms.Count, + 16, + Allocator.Persistent + ); + + _transformAccessArray = new TransformAccessArray(transforms.Count); + + for (var i = 0; i < transforms.Count; i++) + { + _transformPointers[i] = transforms[i].GetUnsafePtr(); + _transformAccessArray.Add(transforms[i].Transform); + } + } + + public void Dispose() + { + ReleaseBuffers(); + _transformRegistry.UnSubscribeOnValueChanged(OnTransformChanged); + } + + private void ReleaseBuffers() + { + if (_transformAccessArray.isCreated) _transformAccessArray.Dispose(); + if (_transformPointers != null) + { + UnsafeUtility.Free(_transformPointers, Allocator.Persistent); + _transformPointers = null; + } + } + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + private struct Job : IJobParallelForTransform + { + [NativeDisableUnsafePtrRestriction] public BlittableTransform** TransformPointers; + + public void Execute(int index, TransformAccess transform) + { + TransformPointers[index]->PullFrom(transform); + } + } + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/Schedulers/PullTransformJobScheduler.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Schedulers/PullTransformJobScheduler.cs.meta new file mode 100644 index 000000000..a8c9666a6 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Schedulers/PullTransformJobScheduler.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 83ca6a73284247c0a809eb9b83b6296b +timeCreated: 1550547066 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Schedulers/PushTransformJobScheduler.cs b/Assets/VRM/Runtime/FastSpringBone/Schedulers/PushTransformJobScheduler.cs new file mode 100644 index 000000000..6d66f61f9 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Schedulers/PushTransformJobScheduler.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +#if ENABLE_SPRINGBONE_BURST +using Unity.Burst; +#endif +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Jobs; +using UnityEngine.Jobs; +using UnityEngine.Profiling; +using VRM.FastSpringBones.Blittables; +using VRM.FastSpringBones.NativeWrappers; +using VRM.FastSpringBones.Registries; + +namespace VRM.FastSpringBones.Schedulers +{ + /// + /// Blittableな世界からGameObjectの世界へTransformを送り込む処理を行うクラス + /// + public sealed unsafe class PushTransformJobScheduler : IDisposable + { + private BlittableTransform** _transformPointers; + private TransformAccessArray _transformAccessArray; + + private readonly CustomSampler _sampler = CustomSampler.Create("Schedule CopyFromTransformJob"); + private readonly TransformRegistry _transformRegistry; + + private bool _dirty = true; + + private IReadOnlyList Targets => _transformRegistry.PushTargets; + + public PushTransformJobScheduler(TransformRegistry transformRegistry) + { + _transformRegistry = transformRegistry; + + _transformRegistry.SubscribeOnValueChanged(OnTransformChanged); + } + + private void OnTransformChanged() + { + _dirty = true; + } + + public JobHandle Schedule(JobHandle dependOn = default(JobHandle)) + { + if (Targets.Count == 0) + { + return dependOn; + } + + _sampler.Begin(); + + // リストが変更されていたらバッファを再構築 + if (_dirty) + { + ReconstructBuffers(); + + _dirty = false; + } + + // Jobを発火 + var job = new Job { TransformPointers = _transformPointers }; + var jobHandle = job.Schedule(_transformAccessArray, dependOn); + + _sampler.End(); + + return jobHandle; + } + + private void ReconstructBuffers() + { + ReleaseBuffers(); + + var transforms = Targets; + _transformPointers = (BlittableTransform**)UnsafeUtility.Malloc( + sizeof(BlittableTransform*) * transforms.Count, + 16, + Allocator.Persistent + ); + + _transformAccessArray = new TransformAccessArray(transforms.Count); + + for (var i = 0; i < transforms.Count; i++) + { + _transformPointers[i] = transforms[i].GetUnsafePtr(); + _transformAccessArray.Add(transforms[i].Transform); + } + } + + public void Dispose() + { + ReleaseBuffers(); + _transformRegistry.UnSubscribeOnValueChanged(OnTransformChanged); + } + + private void ReleaseBuffers() + { + if (_transformAccessArray.isCreated) _transformAccessArray.Dispose(); + if (_transformPointers != null) + { + UnsafeUtility.Free(_transformPointers, Allocator.Persistent); + _transformPointers = null; + } + } + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + private struct Job : IJobParallelForTransform + { + [NativeDisableUnsafePtrRestriction] public BlittableTransform** TransformPointers; + + public void Execute(int index, TransformAccess transform) + { + TransformPointers[index]->PushTo(transform); + } + } + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/Schedulers/PushTransformJobScheduler.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Schedulers/PushTransformJobScheduler.cs.meta new file mode 100644 index 000000000..75f7c9618 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Schedulers/PushTransformJobScheduler.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5a12fcea984d4387a5f3d0f5291df34e +timeCreated: 1550717407 \ No newline at end of file diff --git a/Assets/VRM/Runtime/FastSpringBone/Schedulers/UpdateSpringBoneJobScheduler.cs b/Assets/VRM/Runtime/FastSpringBone/Schedulers/UpdateSpringBoneJobScheduler.cs new file mode 100644 index 000000000..74297dc2d --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Schedulers/UpdateSpringBoneJobScheduler.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +#if ENABLE_SPRINGBONE_BURST +using Unity.Burst; +#endif +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Jobs; +using UnityEngine; +using UnityEngine.Profiling; +using VRM.FastSpringBones.Blittables; +using VRM.FastSpringBones.NativeWrappers; +using VRM.FastSpringBones.Registries; + +namespace VRM.FastSpringBones.Schedulers +{ + /// + /// SpringBoneを更新する処理を行うクラス + /// + public sealed unsafe class UpdateSpringBoneJobScheduler : IDisposable + { + private BlittableRootBone** _rootBonePointers; + + private readonly RootBoneRegistry _rootBoneRegistry; + private readonly CustomSampler _sampler = CustomSampler.Create("Schedule CopyFromTransformJob"); + + private bool _dirty = true; + + private IReadOnlyList> Targets => _rootBoneRegistry.Items; + + public UpdateSpringBoneJobScheduler(RootBoneRegistry rootBoneRegistry) + { + _rootBoneRegistry = rootBoneRegistry; + + _rootBoneRegistry.SubscribeOnValueChanged(OnRootBoneChanged); + } + + public void Dispose() + { + ReleaseBuffer(); + _rootBoneRegistry.UnSubscribeOnValueChanged(OnRootBoneChanged); + } + + private void OnRootBoneChanged() + { + _dirty = true; + } + + public JobHandle Schedule(JobHandle dependOn = default(JobHandle)) + { + if (Targets.Count == 0) + { + return dependOn; + } + + _sampler.Begin(); + + // リストが変更されていたらバッファを再構築 + if (_dirty) + { + ReconstructBuffers(); + + _dirty = false; + } + + // Jobを発火 + var job = new Job { RootBonePointers = _rootBonePointers, DeltaTime = Time.deltaTime }; + var jobHandle = job.Schedule(Targets.Count, 0, dependOn); + + _sampler.End(); + + return jobHandle; + } + + private void ReconstructBuffers() + { + ReleaseBuffer(); + + _rootBonePointers = (BlittableRootBone**)UnsafeUtility.Malloc( + sizeof(BlittableTransform*) * Targets.Count, + 16, + Allocator.Persistent + ); + + for (var i = 0; i < Targets.Count; i++) + { + _rootBonePointers[i] = Targets[i].GetUnsafePtr(); + } + } + + private void ReleaseBuffer() + { + if (_rootBonePointers == null) return; + UnsafeUtility.Free(_rootBonePointers, Allocator.Persistent); + _rootBonePointers = null; + } + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + private struct Job : IJobParallelFor + { + [NativeDisableUnsafePtrRestriction] public BlittableRootBone** RootBonePointers; + public float DeltaTime; + + public void Execute(int index) + { + // 各点を更新する + RootBonePointers[index]->Update(DeltaTime); + } + } + } +} diff --git a/Assets/VRM/Runtime/FastSpringBone/Schedulers/UpdateSpringBoneJobScheduler.cs.meta b/Assets/VRM/Runtime/FastSpringBone/Schedulers/UpdateSpringBoneJobScheduler.cs.meta new file mode 100644 index 000000000..2d47c1232 --- /dev/null +++ b/Assets/VRM/Runtime/FastSpringBone/Schedulers/UpdateSpringBoneJobScheduler.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a6b730c674ce4484862ddee8459c8598 +timeCreated: 1549516763 \ No newline at end of file From 0025182b91ca9ff85678407bca0b775151b4ad62 Mon Sep 17 00:00:00 2001 From: notargs Date: Wed, 29 Sep 2021 16:14:41 +0900 Subject: [PATCH 2/6] Add VRM FastSpringBone support --- .../SpringBone/FastSpringBoneDisposer.cs | 27 ++++ .../SpringBone/FastSpringBoneDisposer.cs.meta | 3 + .../SpringBone/FastSpringBoneReplacer.cs | 130 ++++++++++++++++++ .../SpringBone/FastSpringBoneReplacer.cs.meta | 11 ++ .../SpringBone/FastSpringBoneService.cs | 54 ++++++++ .../SpringBone/FastSpringBoneService.cs.meta | 3 + Assets/VRM/Runtime/VRM.asmdef | 3 +- 7 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 Assets/VRM/Runtime/SpringBone/FastSpringBoneDisposer.cs create mode 100644 Assets/VRM/Runtime/SpringBone/FastSpringBoneDisposer.cs.meta create mode 100644 Assets/VRM/Runtime/SpringBone/FastSpringBoneReplacer.cs create mode 100644 Assets/VRM/Runtime/SpringBone/FastSpringBoneReplacer.cs.meta create mode 100644 Assets/VRM/Runtime/SpringBone/FastSpringBoneService.cs create mode 100644 Assets/VRM/Runtime/SpringBone/FastSpringBoneService.cs.meta diff --git a/Assets/VRM/Runtime/SpringBone/FastSpringBoneDisposer.cs b/Assets/VRM/Runtime/SpringBone/FastSpringBoneDisposer.cs new file mode 100644 index 000000000..ce0a464d1 --- /dev/null +++ b/Assets/VRM/Runtime/SpringBone/FastSpringBoneDisposer.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace VRM +{ + /// + /// FastSpringBoneに関連して、特定のGameObjectと紐付いたIDisposableの破棄を担当するクラス + /// + public sealed class FastSpringBoneDisposer : MonoBehaviour + { + private readonly List _disposables = new List(); + + public void Add(IDisposable disposable) + { + _disposables.Add(disposable); + } + + private void OnDestroy() + { + foreach (var disposable in _disposables) + { + disposable.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/SpringBone/FastSpringBoneDisposer.cs.meta b/Assets/VRM/Runtime/SpringBone/FastSpringBoneDisposer.cs.meta new file mode 100644 index 000000000..7f55e4b79 --- /dev/null +++ b/Assets/VRM/Runtime/SpringBone/FastSpringBoneDisposer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0b96d696de06439e97ac33ed2d890c88 +timeCreated: 1632893490 \ No newline at end of file diff --git a/Assets/VRM/Runtime/SpringBone/FastSpringBoneReplacer.cs b/Assets/VRM/Runtime/SpringBone/FastSpringBoneReplacer.cs new file mode 100644 index 000000000..356ab345c --- /dev/null +++ b/Assets/VRM/Runtime/SpringBone/FastSpringBoneReplacer.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using UnityEngine; +using VRM.FastSpringBones.Blittables; +using VRM.FastSpringBones.Components; +using VRMShaders; +using Object = UnityEngine.Object; + +namespace VRM +{ + /// + /// 指定されたGameObject内にあるSpringBoneをFastSpringBoneに差し替えるユーティリティ + /// + public static class FastSpringBoneReplacer + { + public static async Task ReplaceAsync(GameObject gameObject, IAwaitCaller awaitCaller = null, CancellationToken token = default) + { + var service = FastSpringBoneService.Instance; + var springBones = gameObject.GetComponentsInChildren(); + var disposer = gameObject.AddComponent(); + + // VRMSpringBoneで動いた後の状態がFastSpringBoneの初期状態にならないようにするためawait UniTask.Yield()する前にVRMSpringBoneをdisableにしておく + foreach (var springBone in springBones) + { + springBone.enabled = false; + }; + + if (awaitCaller != null) + { + await awaitCaller.NextFrame(); + token.ThrowIfCancellationRequested(); + } + + var vrmColliderGroups = gameObject.GetComponentsInChildren(); + var colliderGroupDictionary = new Dictionary(); + + // Colliderを差し替える + foreach (var vrmColliderGroup in vrmColliderGroups) + { + if (awaitCaller != null) + { + await awaitCaller.NextFrame(); + token.ThrowIfCancellationRequested(); + } + + var fastSpringBoneCollider = vrmColliderGroup.gameObject.AddComponent(); + fastSpringBoneCollider.Initialize( + service.TransformRegistry, + vrmColliderGroup.Colliders + .Select(data => new BlittableCollider(data.Offset, data.Radius)) + .ToArray() + ); + colliderGroupDictionary[vrmColliderGroup] = fastSpringBoneCollider; + } + + var springRootBones = + ( + from springBone in springBones + from rootBone in springBone.RootBones + select (springBone, rootBone) + ).ToList(); + + for (var i = 0; i < springRootBones.Count; i++) + { + var current = springRootBones[i]; + + // 他のRootBoneのどれかが、自分の親(もしくは同じTransform)なら自分自身を削除する + if (springRootBones + .Where(other => other != current) + .Any(other => current.rootBone.IsChildOf(other.rootBone))) + { + springRootBones.RemoveAt(i); + --i; + } + } + + if (awaitCaller != null) + { + await awaitCaller.NextFrame(); + token.ThrowIfCancellationRequested(); + } + token.ThrowIfCancellationRequested(); + + foreach (var (vrmSpringBone, rootBoneTransform) in springRootBones) + { + // FastSpringRootBoneに差し替える + var fastSpringRootBone = + new FastSpringRootBone( + service.TransformRegistry, + rootBoneTransform, + service.RootBoneRegistry, + service.ColliderGroupRegistry); + disposer.Add(fastSpringRootBone); + + var colliderGroups = + vrmSpringBone.ColliderGroups != null + ? vrmSpringBone.ColliderGroups.Select(group => colliderGroupDictionary[@group]).ToArray() + : Array.Empty(); + + fastSpringRootBone.Initialize( + vrmSpringBone.m_gravityPower, + vrmSpringBone.m_gravityDir, + vrmSpringBone.m_dragForce, + vrmSpringBone.m_stiffnessForce, + colliderGroups, + vrmSpringBone.m_hitRadius, + vrmSpringBone.m_center + ); + + Object.Destroy(vrmSpringBone); + + if (awaitCaller != null) + { + await awaitCaller.NextFrame(); + token.ThrowIfCancellationRequested(); + } + token.ThrowIfCancellationRequested(); + } + + // Colliderを削除 + foreach (var vrmSpringBoneColliderGroup in vrmColliderGroups) + { + Object.Destroy(vrmSpringBoneColliderGroup); + } + } + } +} diff --git a/Assets/VRM/Runtime/SpringBone/FastSpringBoneReplacer.cs.meta b/Assets/VRM/Runtime/SpringBone/FastSpringBoneReplacer.cs.meta new file mode 100644 index 000000000..76ca1edb5 --- /dev/null +++ b/Assets/VRM/Runtime/SpringBone/FastSpringBoneReplacer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a344a05a3634bac419be8a218d8b85d6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRM/Runtime/SpringBone/FastSpringBoneService.cs b/Assets/VRM/Runtime/SpringBone/FastSpringBoneService.cs new file mode 100644 index 000000000..86fab4112 --- /dev/null +++ b/Assets/VRM/Runtime/SpringBone/FastSpringBoneService.cs @@ -0,0 +1,54 @@ +using UnityEngine; +using VRM.FastSpringBones.Components; +using VRM.FastSpringBones.Registries; + +namespace VRM +{ + /// + /// Scene 上に単一で存在する、FastSpringBone の ServiceLocator 兼 EntryPoint + /// + public class FastSpringBoneService : MonoBehaviour + { + public RootBoneRegistry RootBoneRegistry { get; private set; } + public TransformRegistry TransformRegistry { get; private set; } + public ColliderGroupRegistry ColliderGroupRegistry { get; private set; } + public FastSpringBoneScheduler FastSpringBoneScheduler { get; private set; } + + private static FastSpringBoneService _instance; + + public static FastSpringBoneService Instance + { + get + { + if (!_instance) + { + var gameObject = new GameObject("FastSpringBone Service"); + DontDestroyOnLoad(gameObject); + _instance = gameObject.AddComponent(); + } + return _instance; + } + } + + /// + /// 専有しているインスタンスを破棄する + /// + public static void Free() + { + Destroy(_instance.gameObject); + _instance = null; + } + + private void Awake() + { + RootBoneRegistry = new RootBoneRegistry(); + TransformRegistry = new TransformRegistry(); + ColliderGroupRegistry = new ColliderGroupRegistry(); + FastSpringBoneScheduler = gameObject.AddComponent(); + FastSpringBoneScheduler.Initialize( + RootBoneRegistry, + TransformRegistry, + ColliderGroupRegistry); + } + } +} \ No newline at end of file diff --git a/Assets/VRM/Runtime/SpringBone/FastSpringBoneService.cs.meta b/Assets/VRM/Runtime/SpringBone/FastSpringBoneService.cs.meta new file mode 100644 index 000000000..8db972822 --- /dev/null +++ b/Assets/VRM/Runtime/SpringBone/FastSpringBoneService.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7c3edad580b54158b37169025a1e207d +timeCreated: 1632894654 \ No newline at end of file diff --git a/Assets/VRM/Runtime/VRM.asmdef b/Assets/VRM/Runtime/VRM.asmdef index 053d4f4d5..c89f8bc23 100644 --- a/Assets/VRM/Runtime/VRM.asmdef +++ b/Assets/VRM/Runtime/VRM.asmdef @@ -5,7 +5,8 @@ "GUID:8d76e605759c3f64a957d63ef96ada7c", "GUID:da3e51d19d51a544fa14d43fee843098", "GUID:301b251fd9834274c9228e0532f444f7", - "GUID:a9bc101fb0471f94a8f99fd242fdd934" + "GUID:a9bc101fb0471f94a8f99fd242fdd934", + "GUID:ac229b552c3025545b074203f857547c" ], "includePlatforms": [], "excludePlatforms": [], From 66557237fdf7d865582d3d1f800e4fa7721d31fe Mon Sep 17 00:00:00 2001 From: notargs Date: Wed, 29 Sep 2021 16:14:55 +0900 Subject: [PATCH 3/6] Update manifest.json --- Packages/manifest.json | 1 + Packages/packages-lock.json | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/Packages/manifest.json b/Packages/manifest.json index 07f53197f..f3278fa9d 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,5 +1,6 @@ { "dependencies": { + "com.unity.burst": "1.4.11", "com.unity.ide.rider": "1.2.1", "com.unity.ide.visualstudio": "2.0.11", "com.unity.ide.vscode": "1.2.3", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 3aa890b3f..2a839c2b5 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -1,5 +1,14 @@ { "dependencies": { + "com.unity.burst": { + "version": "1.4.11", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.mathematics": "1.2.1" + }, + "url": "https://packages.unity.com" + }, "com.unity.ext.nunit": { "version": "1.0.6", "depth": 1, @@ -32,6 +41,13 @@ "dependencies": {}, "url": "https://packages.unity.com" }, + "com.unity.mathematics": { + "version": "1.2.1", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, "com.unity.postprocessing": { "version": "3.1.1", "depth": 0, From db1f914aac30fc867c3635ece1a88ac988ab40fa Mon Sep 17 00:00:00 2001 From: notargs Date: Wed, 29 Sep 2021 16:15:54 +0900 Subject: [PATCH 4/6] Add fastSpringBone support to sample --- .../Samples/SimpleViewer/SimpleViewer.unity | 482 +++++++++++++++++- Assets/VRM/Samples/SimpleViewer/ViewerUI.cs | 16 + 2 files changed, 492 insertions(+), 6 deletions(-) diff --git a/Assets/VRM/Samples/SimpleViewer/SimpleViewer.unity b/Assets/VRM/Samples/SimpleViewer/SimpleViewer.unity index 9b0860765..272c3b778 100644 --- a/Assets/VRM/Samples/SimpleViewer/SimpleViewer.unity +++ b/Assets/VRM/Samples/SimpleViewer/SimpleViewer.unity @@ -867,8 +867,11 @@ RectTransform: - {fileID: 597950322} - {fileID: 935566651} - {fileID: 634488421} - - {fileID: 1923377807} - {fileID: 630871733} + - {fileID: 1365661828} + - {fileID: 1329594714} + - {fileID: 1391337186} + - {fileID: 1923377807} m_Father: {fileID: 124675794} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -1426,7 +1429,7 @@ RectTransform: - {fileID: 1736108988} - {fileID: 13043734} m_Father: {fileID: 339774397} - m_RootOrder: 11 + m_RootOrder: 10 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -1682,6 +1685,84 @@ MonoBehaviour: m_ChildControlHeight: 0 m_ChildScaleWidth: 0 m_ChildScaleHeight: 0 +--- !u!1 &668840864 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 668840865} + - component: {fileID: 668840867} + - component: {fileID: 668840866} + m_Layer: 5 + m_Name: Label + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &668840865 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 668840864} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1391337186} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 9, y: -0.5} + m_SizeDelta: {x: -28, y: -3} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &668840866 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 668840864} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Use FastSpringBone +--- !u!222 &668840867 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 668840864} + m_CullTransparentMesh: 0 --- !u!1 &773923918 GameObject: m_ObjectHideFlags: 0 @@ -2325,9 +2406,7 @@ MonoBehaviour: m_HorizontalOverflow: 0 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: 'ResetSpringBone - -' + m_Text: ResetSpringBone --- !u!222 &919548010 CanvasRenderer: m_ObjectHideFlags: 0 @@ -3360,6 +3439,80 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1140410863} m_CullTransparentMesh: 0 +--- !u!1 &1160967486 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1160967487} + - component: {fileID: 1160967489} + - component: {fileID: 1160967488} + m_Layer: 5 + m_Name: Checkmark + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1160967487 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1160967486} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1808134149} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1160967488 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1160967486} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10901, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1160967489 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1160967486} + m_CullTransparentMesh: 0 --- !u!1 &1166391798 GameObject: m_ObjectHideFlags: 0 @@ -4142,6 +4295,247 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1322834809} m_CullTransparentMesh: 0 +--- !u!1 &1329594713 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1329594714} + - component: {fileID: 1329594716} + - component: {fileID: 1329594715} + m_Layer: 5 + m_Name: _SpringBone_ + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1329594714 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1329594713} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 339774397} + m_RootOrder: 12 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 178, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1329594715 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1329594713} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u30B9\u30D7\u30EA\u30F3\u30B0\u30DC\u30FC\u30F3" +--- !u!222 &1329594716 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1329594713} + m_CullTransparentMesh: 0 +--- !u!1 &1365661827 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1365661828} + - component: {fileID: 1365661830} + - component: {fileID: 1365661829} + m_Layer: 5 + m_Name: '_ ' + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1365661828 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1365661827} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 339774397} + m_RootOrder: 11 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 178, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1365661829 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1365661827} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 1 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1365661830 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1365661827} + m_CullTransparentMesh: 0 +--- !u!1 &1391337185 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1391337186} + - component: {fileID: 1391337187} + m_Layer: 5 + m_Name: UseFastSpringBone + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1391337186 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1391337185} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1808134149} + - {fileID: 668840865} + m_Father: {fileID: 339774397} + m_RootOrder: 13 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 162, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1391337187 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1391337185} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9085046f02f69544eb97fd06b6048fe2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1808134150} + toggleTransition: 1 + graphic: {fileID: 1160967488} + m_Group: {fileID: 0} + onValueChanged: + m_PersistentCalls: + m_Calls: [] + m_IsOn: 1 --- !u!1 &1476033060 GameObject: m_ObjectHideFlags: 0 @@ -4981,6 +5375,7 @@ MonoBehaviour: m_enableLipSync: {fileID: 935566650} m_enableAutoBlink: {fileID: 634488422} m_useUrpMaterial: {fileID: 630871734} + m_useFastSpringBone: {fileID: 1391337187} m_src: {fileID: 0} m_target: {fileID: 802105000} Root: {fileID: 124675793} @@ -5090,6 +5485,81 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_IsOn: 0 +--- !u!1 &1808134148 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1808134149} + - component: {fileID: 1808134151} + - component: {fileID: 1808134150} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1808134149 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1808134148} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1160967487} + m_Father: {fileID: 1391337186} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 10, y: -10} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1808134150 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1808134148} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1808134151 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1808134148} + m_CullTransparentMesh: 0 --- !u!1 &1866921957 GameObject: m_ObjectHideFlags: 0 @@ -5354,7 +5824,7 @@ RectTransform: m_Children: - {fileID: 919548008} m_Father: {fileID: 339774397} - m_RootOrder: 10 + m_RootOrder: 14 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} diff --git a/Assets/VRM/Samples/SimpleViewer/ViewerUI.cs b/Assets/VRM/Samples/SimpleViewer/ViewerUI.cs index 3c9ade18c..11027f6ce 100644 --- a/Assets/VRM/Samples/SimpleViewer/ViewerUI.cs +++ b/Assets/VRM/Samples/SimpleViewer/ViewerUI.cs @@ -30,6 +30,9 @@ namespace VRM.SimpleViewer [SerializeField] Toggle m_useUrpMaterial = default; + + [SerializeField] + Toggle m_useFastSpringBone = default; #endregion [SerializeField] @@ -172,6 +175,7 @@ namespace VRM.SimpleViewer m_reset = buttons.First(x => x.name == "ResetSpringBone"); var toggles = GameObject.FindObjectsOfType(); + m_useFastSpringBone = toggles.First(x => x.name == "UseFastSpringBone"); m_enableLipSync = toggles.First(x => x.name == "EnableLipSync"); m_enableAutoBlink = toggles.First(x => x.name == "EnableAutoBlink"); @@ -300,6 +304,8 @@ namespace VRM.SimpleViewer m_version.text = string.Format("VRMViewer {0}.{1}", VRMVersion.MAJOR, VRMVersion.MINOR); m_open.onClick.AddListener(OnOpenClicked); + m_useFastSpringBone.onValueChanged.AddListener(OnUseFastSpringBoneValueChanged); + OnUseFastSpringBoneValueChanged(m_useFastSpringBone.isOn); m_reset.onClick.AddListener(() => m_loaded.OnResetClicked()); @@ -381,6 +387,11 @@ namespace VRM.SimpleViewer } } + void OnUseFastSpringBoneValueChanged(bool flag) + { + m_reset.gameObject.SetActive(!flag); + } + static IMaterialDescriptorGenerator GetGltfMaterialGenerator(bool useUrp) { if (useUrp) @@ -467,6 +478,11 @@ namespace VRM.SimpleViewer m_loaded = null; } + if (m_useFastSpringBone.isOn) + { + FastSpringBoneReplacer.ReplaceAsync(instance.Root); + } + instance.EnableUpdateWhenOffscreen(); instance.ShowMeshes(); From 4f272885c0171e81682e5311e197da81cbef6d74 Mon Sep 17 00:00:00 2001 From: notargs Date: Wed, 29 Sep 2021 16:16:06 +0900 Subject: [PATCH 5/6] Add meta file --- Assets/VRM/Samples/SpringBone.meta | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Assets/VRM/Samples/SpringBone.meta diff --git a/Assets/VRM/Samples/SpringBone.meta b/Assets/VRM/Samples/SpringBone.meta new file mode 100644 index 000000000..77a337faa --- /dev/null +++ b/Assets/VRM/Samples/SpringBone.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3fc3f1af567d73f41a5172249769f047 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 95a7999c9418c93765a893d01ff2032694d2389d Mon Sep 17 00:00:00 2001 From: notargs Date: Wed, 29 Sep 2021 16:35:28 +0900 Subject: [PATCH 6/6] Fix comment --- .../FastSpringBone/NativeWrappers/NativeColliderGroups.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroups.cs b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroups.cs index d3d75e220..751dfd571 100644 --- a/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroups.cs +++ b/Assets/VRM/Runtime/FastSpringBone/NativeWrappers/NativeColliderGroups.cs @@ -16,8 +16,8 @@ namespace VRM.FastSpringBones.NativeWrappers private NativeArray _colliderGroupArray; private IReadOnlyList _colliderGroups; - //FIXME: Disposeされた後にUpdateColliderGroupsが呼ばれるのをとりあえず防ぐためのフラグ - private bool _isDisposed = false; + //Disposeされた後にUpdateColliderGroupsが呼ばれるのを防ぐためのフラグ + private bool _isDisposed; public BlittableColliderGroups* GetUnsafePtr() => _nativePointer.GetUnsafePtr(); public void DrawGizmos() => _nativePointer.Value.DrawGizmos();