From 82e4d99e1b08e6b3d38500fd7b08da01518adc3b Mon Sep 17 00:00:00 2001 From: notargs Date: Tue, 5 Oct 2021 18:51:35 +0900 Subject: [PATCH] Add FastSpringBoneBufferCombiner --- .../System/FastSpringBoneBufferCombiner.cs | 185 ++++++++++++++++++ .../FastSpringBoneBufferCombiner.cs.meta | 3 + .../System/UpdateFastSpringBoneJob.cs | 5 +- 3 files changed, 190 insertions(+), 3 deletions(-) create mode 100644 Assets/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs create mode 100644 Assets/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs.meta diff --git a/Assets/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs b/Assets/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs new file mode 100644 index 000000000..8af7f1988 --- /dev/null +++ b/Assets/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs @@ -0,0 +1,185 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.Collections; +using UnityEngine; +using UnityEngine.Jobs; +using UnityEngine.Profiling; +using UniVRM10.FastSpringBones.Blittables; + +namespace UniVRM10.FastSpringBones.System +{ + /// + /// FastSpringBoneの処理に利用するバッファを全て結合して持つクラス + /// + public sealed class FastSpringBoneBufferCombiner : IDisposable + { + private NativeArray _springs; + private NativeArray _joints; + private NativeArray _transforms; + private TransformAccessArray _transformAccessArray; + private NativeArray _colliders; + private NativeArray _logics; + + private readonly LinkedList _fastSpringBoneScopes = new LinkedList(); + + private bool _isDirty; + + public NativeArray Springs => _springs; + public NativeArray Joints => _joints; + public NativeArray Transforms => _transforms; + public TransformAccessArray TransformAccessArray => _transformAccessArray; + public NativeArray Colliders => _colliders; + public NativeArray Logics => _logics; + + public void Register(FastSpringBoneScope scope) + { + _fastSpringBoneScopes.AddLast(scope); + _isDirty = true; + } + + public void Unregister(FastSpringBoneScope scope) + { + _fastSpringBoneScopes.Remove(scope); + _isDirty = true; + } + + /// + /// 変更があったならばバッファを再構築する + /// + public void ReconstructIfDirty() + { + if (_isDirty) + { + ReconstructBuffers(); + _isDirty = false; + } + } + + /// + /// バッファを再構築する + /// TODO: 最適化 + /// + private void ReconstructBuffers() + { + Profiler.BeginSample("FastSpringBone.ReconstructBuffers"); + DisposeAllBuffers(); + + var springs = _fastSpringBoneScopes.SelectMany(scope => scope.Springs).ToArray(); + + // Transformの列挙 + var transformHashSet = new HashSet(); + foreach (var spring in springs) + { + foreach (var joint in spring.joints) + { + transformHashSet.Add(joint.Transform); + if (joint.Transform.parent != null) transformHashSet.Add(joint.Transform.parent); + } + foreach (var collider in spring.colliders) + { + transformHashSet.Add(collider.Transform); + } + + if (spring.center != null) transformHashSet.Add(spring.center); + } + var transforms = transformHashSet.ToArray(); + var transformIndexDictionary = transforms.Select((trs, index) => (trs, index)) + .ToDictionary(tuple => tuple.trs, tuple => tuple.index); + + // 各種bufferの構築 + var blittableColliders = new List(); + var blittableJoints = new List(); + var blittableSprings = new List(); + var blittableLogics = new List(); + + foreach (var spring in springs) + { + var blittableSpring = new BlittableSpring + { + colliderSpan = new BlittableSpan + { + startIndex = blittableColliders.Count, + count = spring.colliders.Length, + }, + logicSpan = new BlittableSpan + { + startIndex = blittableJoints.Count, + count = spring.joints.Length - 1, + }, + centerTransformIndex = spring.center ? transformIndexDictionary[spring.center] : -1 + }; + blittableSprings.Add(blittableSpring); + + blittableColliders.AddRange(spring.colliders.Select(collider => + { + var blittable = collider.Collider; + blittable.transformIndex = transformIndexDictionary[collider.Transform]; + return blittable; + })); + blittableJoints.AddRange(spring.joints.Take(spring.joints.Length - 1).Select(joint => + { + var blittable = joint.Joint; + return blittable; + })); + + for (var i = 0; i < spring.joints.Length - 1; ++i) + { + var joint = spring.joints[i]; + var tailJoint = spring.joints[i + 1]; + var localPosition = tailJoint.Transform.localPosition; + var scale = tailJoint.Transform.lossyScale; + var localChildPosition = + new Vector3( + localPosition.x * scale.x, + localPosition.y * scale.y, + localPosition.z * scale.z + ); + + var worldChildPosition = joint.Transform.TransformPoint(localChildPosition); + var currentTail = spring.center != null + ? spring.center.InverseTransformPoint(worldChildPosition) + : worldChildPosition; + var parent = joint.Transform.parent; + blittableLogics.Add(new BlittableLogic + { + headTransformIndex = transformIndexDictionary[joint.Transform], + parentTransformIndex = parent != null ? transformIndexDictionary[parent] : -1, + currentTail = currentTail, + prevTail = currentTail, + localRotation = joint.Transform.localRotation, + boneAxis = localChildPosition.normalized, + length = localChildPosition.magnitude + }); + } + } + + // 各種bufferの初期化 + _springs = new NativeArray(blittableSprings.ToArray(), Allocator.Persistent); + + _joints = new NativeArray(blittableJoints.ToArray(), Allocator.Persistent); + _colliders = new NativeArray(blittableColliders.ToArray(), Allocator.Persistent); + _logics = new NativeArray(blittableLogics.ToArray(), Allocator.Persistent); + + _transforms = new NativeArray(transforms.Length, Allocator.Persistent); + _transformAccessArray = new TransformAccessArray(transforms.ToArray()); + + Profiler.EndSample(); + } + + private void DisposeAllBuffers() + { + if (_springs.IsCreated) _springs.Dispose(); + if (_joints.IsCreated) _joints.Dispose(); + if (_transforms.IsCreated) _transforms.Dispose(); + if (_transformAccessArray.isCreated) _transformAccessArray.Dispose(); + if (_colliders.IsCreated) _colliders.Dispose(); + if (_logics.IsCreated) _logics.Dispose(); + } + + public void Dispose() + { + DisposeAllBuffers(); + } + } +} \ No newline at end of file diff --git a/Assets/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs.meta b/Assets/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs.meta new file mode 100644 index 000000000..ce9f4ec5a --- /dev/null +++ b/Assets/VRM10/Runtime/FastSpringBone/System/FastSpringBoneBufferCombiner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2b0299bf5bfe431e8e18a9b033b719a3 +timeCreated: 1633072502 \ No newline at end of file diff --git a/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs b/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs index b9ae16115..33b2246c2 100644 --- a/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs +++ b/Assets/VRM10/Runtime/FastSpringBone/System/UpdateFastSpringBoneJob.cs @@ -14,13 +14,12 @@ namespace UniVRM10.FastSpringBones.System public struct UpdateFastSpringBoneJob : IJobParallelFor { [ReadOnly] public NativeArray Springs; - [ReadOnly] public NativeArray Joints; + [ReadOnly] public NativeArray Colliders; + [NativeDisableParallelForRestriction] public NativeArray Logics; [NativeDisableParallelForRestriction] public NativeArray Transforms; - [ReadOnly] public NativeArray Colliders; - public float DeltaTime; public void Execute(int index)