From 6917f195f18d6d505ed0b66e0ae623ce650c5a85 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 1 Oct 2024 19:10:35 +0900 Subject: [PATCH 1/2] =?UTF-8?q?FastSpringBoneBufferCombiner=20=E3=81=AE?= =?UTF-8?q?=E8=B2=AC=E5=8B=99=E3=82=92=E5=88=86=E5=89=B2=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FastSpringBoneCombinedBuffer 統合バッファ - FastSpringBoneBufferCombiner 統合前バッファの登録管理 --- .../FastSpringBoneBufferCombiner.cs | 323 +---------------- .../FastSpringBoneConbinedBuffer.cs | 334 ++++++++++++++++++ .../FastSpringBoneConbinedBuffer.cs.meta | 11 + .../SpringBoneJobs/FastSpringBoneScheduler.cs | 49 +-- 4 files changed, 390 insertions(+), 327 deletions(-) create mode 100644 Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneConbinedBuffer.cs create mode 100644 Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneConbinedBuffer.cs.meta diff --git a/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneBufferCombiner.cs b/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneBufferCombiner.cs index 6e9f776146..b043f01334 100644 --- a/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneBufferCombiner.cs +++ b/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneBufferCombiner.cs @@ -1,67 +1,26 @@ using System; using System.Collections.Generic; -using System.Linq; -using Unity.Collections; using Unity.Jobs; -using UnityEngine; -using UnityEngine.Jobs; using UnityEngine.Profiling; -using UniGLTF.SpringBoneJobs.Blittables; using UniGLTF.SpringBoneJobs.InputPorts; -#if ENABLE_SPRINGBONE_BURST -using Unity.Burst; -#endif namespace UniGLTF.SpringBoneJobs { /// - /// FastSpringBoneの処理に利用するバッファを全て結合して持つクラス + /// CombinedBuffer 構築を管理する + /// + /// - FastSpringBoneBuffer(Vrm-1.0 一体分の情報)を登録・削除する。 + /// - 再構築する。登録・削除後に反映するために呼び出す。 + /// - (TODO) FastSpringBoneBuffer一体分の回転初期化を実行する。 + /// /// public sealed class FastSpringBoneBufferCombiner : IDisposable { - // 長さと index 同じ - private NativeArray _logics; - private NativeArray _joints; - - private NativeArray _prevTails; - private NativeArray _currentTails; - private NativeArray _nextTails; - - private NativeArray _springs; - - private NativeArray _colliders; - - private NativeArray _transforms; - private TransformAccessArray _transformAccessArray; - + private FastSpringBoneCombinedBuffer _combinedBuffer; + public FastSpringBoneCombinedBuffer Combined => _combinedBuffer; private readonly LinkedList _buffers = new LinkedList(); - private FastSpringBoneBuffer[] _batchedBuffers; - private int[] _batchedBufferLogicSizes; - private bool _isDirty; - - public NativeArray Logics => _logics; - public NativeArray Joints => _joints; - public NativeArray PrevTails => _prevTails; - public NativeArray CurrentTails => _currentTails; - public NativeArray NextTails => _nextTails; - - public NativeArray Springs => _springs; - - public NativeArray Colliders => _colliders; - - public NativeArray Transforms => _transforms; - public TransformAccessArray TransformAccessArray => _transformAccessArray; - - public bool HasBuffer => _batchedBuffers != null && _batchedBuffers.Length > 0; - - public void FlipBuffer() - { - var tmp = _prevTails; - _prevTails = _currentTails; - _currentTails = _nextTails; - _nextTails = tmp; - } + public bool HasBuffer => _buffers.Count > 0 && _combinedBuffer != null; public void Register(FastSpringBoneBuffer buffer) { @@ -90,27 +49,6 @@ public JobHandle ReconstructIfDirty(JobHandle handle) return handle; } - /// - /// バッチングされたバッファから、個々のバッファへと値を戻す - /// バッファの再構築前にこの処理を行わないと、揺れの状態がリセットされてしまい、不自然な挙動になる - /// - private void SaveToSourceBuffer() - { - if (_batchedBuffers == null) return; - - var logicsIndex = 0; - for (var i = 0; i < _batchedBuffers.Length; ++i) - { - var length = _batchedBufferLogicSizes[i]; - if (!_batchedBuffers[i].IsDisposed && length > 0) - { - NativeArray.Copy(_logics, logicsIndex, _batchedBuffers[i].Logics, 0, length); - } - - logicsIndex += length; - } - } - /// /// バッファを再構築する /// @@ -118,254 +56,31 @@ private JobHandle ReconstructBuffers(JobHandle handle) { Profiler.BeginSample("FastSpringBone.ReconstructBuffers"); - Profiler.BeginSample("FastSpringBone.ReconstructBuffers.SaveToSourceBuffer"); - SaveToSourceBuffer(); - Profiler.EndSample(); - Profiler.BeginSample("FastSpringBone.ReconstructBuffers.DisposeBuffers"); - DisposeAllBuffers(); - Profiler.EndSample(); - - var springsCount = 0; - var collidersCount = 0; - var logicsCount = 0; - var transformsCount = 0; - - Profiler.BeginSample("FastSpringBone.ReconstructBuffers.CopyToBatchedBuffers"); - _batchedBuffers = _buffers.ToArray(); - _batchedBufferLogicSizes = _batchedBuffers.Select(buffer => buffer.Logics.Length).ToArray(); - Profiler.EndSample(); - - // バッファを数える - Profiler.BeginSample("FastSpringBone.ReconstructBuffers.CountBufferSize"); - foreach (var buffer in _buffers) - { - springsCount += buffer.Springs.Length; - collidersCount += buffer.Colliders.Length; - logicsCount += buffer.Logics.Length; - transformsCount += buffer.BlittableTransforms.Length; - } - Profiler.EndSample(); - - // バッファの構築 - Profiler.BeginSample("FastSpringBone.ReconstructBuffers.CreateBuffers"); - - _logics = new NativeArray(logicsCount, Allocator.Persistent); - _joints = new NativeArray(logicsCount, Allocator.Persistent); - _prevTails = new NativeArray(logicsCount, Allocator.Persistent); - _currentTails = new NativeArray(logicsCount, Allocator.Persistent); - _nextTails = new NativeArray(logicsCount, Allocator.Persistent); - - _springs = new NativeArray(springsCount, Allocator.Persistent); - - _colliders = new NativeArray(collidersCount, Allocator.Persistent); - - _transforms = new NativeArray(transformsCount, Allocator.Persistent); - Profiler.EndSample(); - - Profiler.BeginSample("FastSpringBone.ReconstructBuffers.ScheduleLoadBufferJobs"); - var springsOffset = 0; - var collidersOffset = 0; - var logicsOffset = 0; - var transformOffset = 0; - for (var i = 0; i < _batchedBuffers.Length; i++) + if (_combinedBuffer is FastSpringBoneCombinedBuffer combined) { - var buffer = _batchedBuffers[i]; - - // バッファの読み込みをスケジュール - handle = new LoadTransformsJob - { - SrcTransforms = buffer.BlittableTransforms, - DestTransforms = new NativeSlice(_transforms, transformOffset, - buffer.BlittableTransforms.Length) - }.Schedule(buffer.BlittableTransforms.Length, 1, handle); - - handle = new LoadSpringsJob - { - SrcSprings = buffer.Springs, - DestSprings = new NativeSlice(_springs, springsOffset, buffer.Springs.Length), - CollidersOffset = collidersOffset, - LogicsOffset = logicsOffset, - TransformOffset = transformOffset, - }.Schedule(buffer.Springs.Length, 1, handle); - - handle = new LoadCollidersJob - { - SrcColliders = buffer.Colliders, - DestColliders = new NativeSlice(_colliders, collidersOffset, buffer.Colliders.Length) - }.Schedule(buffer.Colliders.Length, 1, handle); - - handle = new OffsetLogicsJob - { - SrcLogics = buffer.Logics, - SrcJoints = buffer.Joints, - - DestLogics = new NativeSlice(_logics, logicsOffset, buffer.Logics.Length), - DestJoints = new NativeSlice(_joints, logicsOffset, buffer.Logics.Length), - }.Schedule(buffer.Logics.Length, 1, handle); + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.SaveToSourceBuffer"); + combined.SaveToSourceBuffer(); + Profiler.EndSample(); - springsOffset += buffer.Springs.Length; - collidersOffset += buffer.Colliders.Length; - logicsOffset += buffer.Logics.Length; - transformOffset += buffer.BlittableTransforms.Length; + // TODO: Dispose せずに再利用? + combined.Dispose(); } - - handle = InitCurrentTails(handle); - - // TransformAccessArrayの構築と並行してJobを行うため、この時点で走らせておく - JobHandle.ScheduleBatchedJobs(); Profiler.EndSample(); - // TransformAccessArrayの構築 - Profiler.BeginSample("FastSpringBone.ReconstructBuffers.LoadTransformAccessArray"); - var transforms = new Transform[transformsCount]; - var transformAccessArrayOffset = 0; - foreach (var buffer in _batchedBuffers) - { - Array.Copy(buffer.Transforms, 0, transforms, transformAccessArrayOffset, buffer.Transforms.Length); - transformAccessArrayOffset += buffer.BlittableTransforms.Length; - } - - _transformAccessArray = new TransformAccessArray(transforms); - Profiler.EndSample(); + handle = FastSpringBoneCombinedBuffer.Create(handle, _buffers, out _combinedBuffer); Profiler.EndSample(); return handle; } - /// - /// Transform から currentTail を更新。 - /// prevTail も同じ内容にする(速度0)。 - /// - /// - /// - public JobHandle InitCurrentTails(JobHandle handle) - { - return new InitCurrentTailsJob - { - Logics = Logics, - Transforms = Transforms, - CurrentTails = CurrentTails, - PrevTails = PrevTails, - NextTails = NextTails, - }.Schedule(Logics.Length, 1, handle); - } - - private void DisposeAllBuffers() - { - if (_logics.IsCreated) _logics.Dispose(); - if (_joints.IsCreated) _joints.Dispose(); - if (_prevTails.IsCreated) _prevTails.Dispose(); - if (_currentTails.IsCreated) _currentTails.Dispose(); - if (_nextTails.IsCreated) _nextTails.Dispose(); - if (_springs.IsCreated) _springs.Dispose(); - if (_colliders.IsCreated) _colliders.Dispose(); - if (_transforms.IsCreated) _transforms.Dispose(); - if (_transformAccessArray.isCreated) _transformAccessArray.Dispose(); - } - public void Dispose() { - DisposeAllBuffers(); - } - -#if ENABLE_SPRINGBONE_BURST - [BurstCompile] -#endif - private struct LoadTransformsJob : IJobParallelFor - { - [ReadOnly] public NativeArray SrcTransforms; - [WriteOnly] public NativeSlice DestTransforms; - - public void Execute(int index) - { - DestTransforms[index] = SrcTransforms[index]; - } - } - -#if ENABLE_SPRINGBONE_BURST - [BurstCompile] -#endif - private struct LoadSpringsJob : IJobParallelFor - { - [ReadOnly] public NativeArray SrcSprings; - [WriteOnly] public NativeSlice DestSprings; - - public int CollidersOffset; - public int LogicsOffset; - public int TransformOffset; - - public void Execute(int index) - { - var spring = SrcSprings[index]; - spring.colliderSpan.startIndex += CollidersOffset; - spring.logicSpan.startIndex += LogicsOffset; - spring.transformIndexOffset = TransformOffset; - DestSprings[index] = spring; - } - } - -#if ENABLE_SPRINGBONE_BURST - [BurstCompile] -#endif - private struct LoadCollidersJob : IJobParallelFor - { - [ReadOnly] public NativeArray SrcColliders; - [WriteOnly] public NativeSlice DestColliders; - - public void Execute(int index) - { - DestColliders[index] = SrcColliders[index]; - } - } - -#if ENABLE_SPRINGBONE_BURST - [BurstCompile] -#endif - private struct OffsetLogicsJob : IJobParallelFor - { - [ReadOnly] public NativeSlice SrcLogics; - [ReadOnly] public NativeSlice SrcJoints; - [WriteOnly] public NativeSlice DestLogics; - [WriteOnly] public NativeSlice DestJoints; - - public void Execute(int index) - { - DestLogics[index] = SrcLogics[index]; - DestJoints[index] = SrcJoints[index]; - } - } - -#if ENABLE_SPRINGBONE_BURST - [BurstCompile] -#endif - private struct InitCurrentTailsJob : IJobParallelFor - { - [ReadOnly] public NativeArray Logics; - [ReadOnly] public NativeArray Transforms; - [WriteOnly] public NativeSlice CurrentTails; - [WriteOnly] public NativeSlice PrevTails; - [WriteOnly] public NativeSlice NextTails; - - public void Execute(int jointIndex) + if (_combinedBuffer is FastSpringBoneCombinedBuffer combined) { - var tailIndex = Logics[jointIndex].tailTransformIndex; - if (tailIndex == -1) - { - // tail 無い - var tail = Transforms[Logics[jointIndex].headTransformIndex]; - CurrentTails[jointIndex] = tail.position; - PrevTails[jointIndex] = tail.position; - NextTails[jointIndex] = tail.position; - } - else - { - var tail = Transforms[tailIndex]; - CurrentTails[jointIndex] = tail.position; - PrevTails[jointIndex] = tail.position; - NextTails[jointIndex] = tail.position; - } + combined.Dispose(); + _combinedBuffer = null; } } } diff --git a/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneConbinedBuffer.cs b/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneConbinedBuffer.cs new file mode 100644 index 0000000000..e0d48ee78f --- /dev/null +++ b/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneConbinedBuffer.cs @@ -0,0 +1,334 @@ +#if ENABLE_SPRINGBONE_BURST +using Unity.Burst; +#endif + +using System; +using System.Collections.Generic; +using System.Linq; +using UniGLTF.SpringBoneJobs.Blittables; +using UniGLTF.SpringBoneJobs.InputPorts; +using Unity.Collections; +using Unity.Jobs; +using UnityEngine; +using UnityEngine.Jobs; +using UnityEngine.Profiling; + +namespace UniGLTF.SpringBoneJobs +{ + /// + /// FastSpringBoneの処理に利用するバッファを全て結合して持つクラス + /// + public class FastSpringBoneCombinedBuffer : IDisposable + { + // 長さと index 同じ + private NativeArray _logics; + private NativeArray _joints; + private NativeArray _prevTails; + private NativeArray _currentTails; + private NativeArray _nextTails; + + private NativeArray _springs; + + private NativeArray _colliders; + + private NativeArray _transforms; + private TransformAccessArray _transformAccessArray; + + public NativeArray Logics => _logics; + public NativeArray Joints => _joints; + public NativeArray PrevTails => _prevTails; + public NativeArray CurrentTails => _currentTails; + public NativeArray NextTails => _nextTails; + + public NativeArray Springs => _springs; + + public NativeArray Colliders => _colliders; + + public NativeArray Transforms => _transforms; + public TransformAccessArray TransformAccessArray => _transformAccessArray; + + // 構築情報 + private FastSpringBoneBuffer[] _batchedBuffers; + private int[] _batchedBufferLogicSizes; + + private FastSpringBoneCombinedBuffer(int logicsCount, int springsCount, int collidersCount, int transformsCount, + FastSpringBoneBuffer[] batchedBuffers, + int[] batchedBufferLogicSizes + ) + { + _logics = new NativeArray(logicsCount, Allocator.Persistent); + _joints = new NativeArray(logicsCount, Allocator.Persistent); + _prevTails = new NativeArray(logicsCount, Allocator.Persistent); + _currentTails = new NativeArray(logicsCount, Allocator.Persistent); + _nextTails = new NativeArray(logicsCount, Allocator.Persistent); + _springs = new NativeArray(springsCount, Allocator.Persistent); + _colliders = new NativeArray(collidersCount, Allocator.Persistent); + _transforms = new NativeArray(transformsCount, Allocator.Persistent); + _batchedBuffers = batchedBuffers; + _batchedBufferLogicSizes = batchedBufferLogicSizes; + } + + internal static JobHandle Create(JobHandle handle, + LinkedList _buffers, out FastSpringBoneCombinedBuffer combined) + { + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.CopyToBatchedBuffers"); + var batchedBuffers = _buffers.ToArray(); + var batchedBufferLogicSizes = batchedBuffers.Select(buffer => buffer.Logics.Length).ToArray(); + Profiler.EndSample(); + + // バッファを数える + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.CountBufferSize"); + var springsCount = 0; + var collidersCount = 0; + var logicsCount = 0; + var transformsCount = 0; + foreach (var buffer in _buffers) + { + springsCount += buffer.Springs.Length; + collidersCount += buffer.Colliders.Length; + logicsCount += buffer.Logics.Length; + transformsCount += buffer.BlittableTransforms.Length; + } + Profiler.EndSample(); + + // バッファの構築 + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.CreateBuffers"); + combined = new FastSpringBoneCombinedBuffer(logicsCount, springsCount, collidersCount, transformsCount, + batchedBuffers, batchedBufferLogicSizes); + Profiler.EndSample(); + + return combined.Batching(handle); + } + + private JobHandle Batching(JobHandle handle) + { + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.ScheduleLoadBufferJobs"); + var springsOffset = 0; + var collidersOffset = 0; + var logicsOffset = 0; + var transformOffset = 0; + for (var i = 0; i < _batchedBuffers.Length; i++) + { + var buffer = _batchedBuffers[i]; + + // バッファの読み込みをスケジュール + handle = new LoadTransformsJob + { + SrcTransforms = buffer.BlittableTransforms, + DestTransforms = new NativeSlice(_transforms, transformOffset, + buffer.BlittableTransforms.Length) + }.Schedule(buffer.BlittableTransforms.Length, 1, handle); + + handle = new LoadSpringsJob + { + SrcSprings = buffer.Springs, + DestSprings = new NativeSlice(_springs, springsOffset, buffer.Springs.Length), + CollidersOffset = collidersOffset, + LogicsOffset = logicsOffset, + TransformOffset = transformOffset, + }.Schedule(buffer.Springs.Length, 1, handle); + + handle = new LoadCollidersJob + { + SrcColliders = buffer.Colliders, + DestColliders = new NativeSlice(_colliders, collidersOffset, buffer.Colliders.Length) + }.Schedule(buffer.Colliders.Length, 1, handle); + + handle = new OffsetLogicsJob + { + SrcLogics = buffer.Logics, + SrcJoints = buffer.Joints, + + DestLogics = new NativeSlice(_logics, logicsOffset, buffer.Logics.Length), + DestJoints = new NativeSlice(_joints, logicsOffset, buffer.Logics.Length), + }.Schedule(buffer.Logics.Length, 1, handle); + + springsOffset += buffer.Springs.Length; + collidersOffset += buffer.Colliders.Length; + logicsOffset += buffer.Logics.Length; + transformOffset += buffer.BlittableTransforms.Length; + } + + handle = InitCurrentTails(handle); + + // TransformAccessArrayの構築と並行してJobを行うため、この時点で走らせておく + JobHandle.ScheduleBatchedJobs(); + Profiler.EndSample(); + + // TransformAccessArrayの構築 + Profiler.BeginSample("FastSpringBone.ReconstructBuffers.LoadTransformAccessArray"); + var transforms = new Transform[_transforms.Length]; + var transformAccessArrayOffset = 0; + foreach (var buffer in _batchedBuffers) + { + Array.Copy(buffer.Transforms, 0, transforms, transformAccessArrayOffset, buffer.Transforms.Length); + transformAccessArrayOffset += buffer.BlittableTransforms.Length; + } + + _transformAccessArray = new TransformAccessArray(transforms); + Profiler.EndSample(); + + return handle; + } + + public void Dispose() + { + if (_logics.IsCreated) _logics.Dispose(); + if (_joints.IsCreated) _joints.Dispose(); + if (_prevTails.IsCreated) _prevTails.Dispose(); + if (_currentTails.IsCreated) _currentTails.Dispose(); + if (_nextTails.IsCreated) _nextTails.Dispose(); + if (_springs.IsCreated) _springs.Dispose(); + if (_colliders.IsCreated) _colliders.Dispose(); + if (_transforms.IsCreated) _transforms.Dispose(); + if (_transformAccessArray.isCreated) _transformAccessArray.Dispose(); + } + + /// + /// バッチングされたバッファから、個々のバッファへと値を戻す + /// Logics to _batchedBuffers[].Logics + /// バッファの再構築前にこの処理を行わないと、揺れの状態がリセットされてしまい、不自然な挙動になる + /// + internal void SaveToSourceBuffer() + { + var logicsIndex = 0; + for (var i = 0; i < _batchedBuffers.Length; ++i) + { + var length = _batchedBufferLogicSizes[i]; + if (!_batchedBuffers[i].IsDisposed && length > 0) + { + NativeArray.Copy(Logics, logicsIndex, _batchedBuffers[i].Logics, 0, length); + } + logicsIndex += length; + } + } + + public void FlipBuffer() + { + var tmp = _prevTails; + _prevTails = _currentTails; + _currentTails = _nextTails; + _nextTails = tmp; + } + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + /// + /// + /// + private struct LoadTransformsJob : IJobParallelFor + { + [ReadOnly] public NativeArray SrcTransforms; + [WriteOnly] public NativeSlice DestTransforms; + + public void Execute(int index) + { + DestTransforms[index] = SrcTransforms[index]; + } + } + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + private struct LoadSpringsJob : IJobParallelFor + { + [ReadOnly] public NativeArray SrcSprings; + [WriteOnly] public NativeSlice DestSprings; + + public int CollidersOffset; + public int LogicsOffset; + public int TransformOffset; + + public void Execute(int index) + { + var spring = SrcSprings[index]; + spring.colliderSpan.startIndex += CollidersOffset; + spring.logicSpan.startIndex += LogicsOffset; + spring.transformIndexOffset = TransformOffset; + DestSprings[index] = spring; + } + } + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + private struct LoadCollidersJob : IJobParallelFor + { + [ReadOnly] public NativeArray SrcColliders; + [WriteOnly] public NativeSlice DestColliders; + + public void Execute(int index) + { + DestColliders[index] = SrcColliders[index]; + } + } + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + private struct OffsetLogicsJob : IJobParallelFor + { + [ReadOnly] public NativeSlice SrcLogics; + [ReadOnly] public NativeSlice SrcJoints; + [WriteOnly] public NativeSlice DestLogics; + [WriteOnly] public NativeSlice DestJoints; + + public void Execute(int index) + { + DestLogics[index] = SrcLogics[index]; + DestJoints[index] = SrcJoints[index]; + } + } + +#if ENABLE_SPRINGBONE_BURST + [BurstCompile] +#endif + private struct InitCurrentTailsJob : IJobParallelFor + { + [ReadOnly] public NativeArray Logics; + [ReadOnly] public NativeArray Transforms; + [WriteOnly] public NativeSlice CurrentTails; + [WriteOnly] public NativeSlice PrevTails; + [WriteOnly] public NativeSlice NextTails; + + public void Execute(int jointIndex) + { + var tailIndex = Logics[jointIndex].tailTransformIndex; + if (tailIndex == -1) + { + // tail 無い + var tail = Transforms[Logics[jointIndex].headTransformIndex]; + CurrentTails[jointIndex] = tail.position; + PrevTails[jointIndex] = tail.position; + NextTails[jointIndex] = tail.position; + } + else + { + var tail = Transforms[tailIndex]; + CurrentTails[jointIndex] = tail.position; + PrevTails[jointIndex] = tail.position; + NextTails[jointIndex] = tail.position; + } + } + } + + /// + /// Transform から currentTail を更新。 + /// prevTail も同じ内容にする(速度0)。 + /// + /// + /// + public JobHandle InitCurrentTails(JobHandle handle) + { + return new InitCurrentTailsJob + { + Logics = Logics, + Transforms = Transforms, + CurrentTails = CurrentTails, + PrevTails = PrevTails, + NextTails = NextTails, + }.Schedule(Logics.Length, 1, handle); + } + } +} \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneConbinedBuffer.cs.meta b/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneConbinedBuffer.cs.meta new file mode 100644 index 0000000000..b87ad22474 --- /dev/null +++ b/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneConbinedBuffer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0485fe3392c9d0246bfb6b44720b8153 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneScheduler.cs b/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneScheduler.cs index b35e7ec991..825707b488 100644 --- a/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneScheduler.cs +++ b/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneScheduler.cs @@ -26,30 +26,33 @@ public JobHandle Schedule(float deltaTime) return handle; } - handle = new PullTransformJob + if (_bufferCombiner.Combined is FastSpringBoneCombinedBuffer combined) { - Transforms = _bufferCombiner.Transforms - }.Schedule(_bufferCombiner.TransformAccessArray, handle); - - _bufferCombiner.FlipBuffer(); - - handle = new UpdateFastSpringBoneJob - { - Joints = _bufferCombiner.Joints, - Logics = _bufferCombiner.Logics, - CurrentTail = _bufferCombiner.CurrentTails, - PrevTail = _bufferCombiner.PrevTails, - NextTail = _bufferCombiner.NextTails, - Springs = _bufferCombiner.Springs, - Colliders = _bufferCombiner.Colliders, - Transforms = _bufferCombiner.Transforms, - DeltaTime = deltaTime, - }.Schedule(_bufferCombiner.Springs.Length, 1, handle); - - handle = new PushTransformJob - { - Transforms = _bufferCombiner.Transforms - }.Schedule(_bufferCombiner.TransformAccessArray, handle); + handle = new PullTransformJob + { + Transforms = combined.Transforms + }.Schedule(combined.TransformAccessArray, handle); + + combined.FlipBuffer(); + + handle = new UpdateFastSpringBoneJob + { + Joints = combined.Joints, + Logics = combined.Logics, + CurrentTail = combined.CurrentTails, + PrevTail = combined.PrevTails, + NextTail = combined.NextTails, + Springs = combined.Springs, + Colliders = combined.Colliders, + Transforms = combined.Transforms, + DeltaTime = deltaTime, + }.Schedule(combined.Springs.Length, 1, handle); + + handle = new PushTransformJob + { + Transforms = combined.Transforms + }.Schedule(combined.TransformAccessArray, handle); + } return handle; } From 5caf987a187c88ef71912c3ceabf67bfee298c18 Mon Sep 17 00:00:00 2001 From: ousttrue Date: Tue, 1 Oct 2024 20:49:02 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[1.0]=20SpringBone=20reset=20=E5=AE=9F?= =?UTF-8?q?=E8=A3=85=E3=81=AA=E3=81=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FastSpringBoneBufferCombiner.cs | 11 +++++++ .../FastSpringBoneConbinedBuffer.cs | 26 +++++++++++++++ .../InputPorts/FastSpringBoneBuffer.cs | 33 ++++--------------- .../Runtime/UniGLTF/IO/ImporterContext.cs | 13 +++++++- .../Vrm10FastSpringboneRuntime.cs | 7 ++-- .../Vrm10FastSpringboneRuntimeStandalone.cs | 7 ++-- Assets/VRM10/Runtime/IO/Vrm10Importer.cs | 17 ++++++++++ 7 files changed, 80 insertions(+), 34 deletions(-) diff --git a/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneBufferCombiner.cs b/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneBufferCombiner.cs index b043f01334..4b0e78d5db 100644 --- a/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneBufferCombiner.cs +++ b/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneBufferCombiner.cs @@ -75,6 +75,17 @@ private JobHandle ReconstructBuffers(JobHandle handle) return handle; } + /// + /// 各Jointのローカルローテーションを初期回転に戻す。spring reset + /// + public void InitializeJointsLocalRotation(FastSpringBoneBuffer model) + { + if (_combinedBuffer is FastSpringBoneCombinedBuffer combined) + { + combined.InitializeJointsLocalRotation(model); + } + } + public void Dispose() { if (_combinedBuffer is FastSpringBoneCombinedBuffer combined) diff --git a/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneConbinedBuffer.cs b/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneConbinedBuffer.cs index e0d48ee78f..284eada615 100644 --- a/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneConbinedBuffer.cs +++ b/Assets/UniGLTF/Runtime/SpringBoneJobs/FastSpringBoneConbinedBuffer.cs @@ -330,5 +330,31 @@ public JobHandle InitCurrentTails(JobHandle handle) NextTails = NextTails, }.Schedule(Logics.Length, 1, handle); } + + public void InitializeJointsLocalRotation(FastSpringBoneBuffer buffer) + { + var logicsIndex = 0; + for (var i = 0; i < _batchedBuffers.Length; ++i) + { + var length = _batchedBufferLogicSizes[i]; + Debug.Assert(length == buffer.Logics.Length); + if (_batchedBuffers[i] == buffer) + { + for (var j = 0; j < length; ++j) + { + var logic = buffer.Logics[j]; + if (logic.tailTransformIndex != -1) + { + var tailPosition = buffer.Transforms[logic.tailTransformIndex].position; + var dst = logicsIndex + j; + // tail 位置を初期化し速度を0にする + _currentTails[dst] = _prevTails[dst] = _nextTails[dst] = tailPosition; + } + } + break; + } + logicsIndex += length; + } + } } } \ No newline at end of file diff --git a/Assets/UniGLTF/Runtime/SpringBoneJobs/InputPorts/FastSpringBoneBuffer.cs b/Assets/UniGLTF/Runtime/SpringBoneJobs/InputPorts/FastSpringBoneBuffer.cs index 35b36dbd81..40493b2946 100644 --- a/Assets/UniGLTF/Runtime/SpringBoneJobs/InputPorts/FastSpringBoneBuffer.cs +++ b/Assets/UniGLTF/Runtime/SpringBoneJobs/InputPorts/FastSpringBoneBuffer.cs @@ -151,42 +151,21 @@ public static IEnumerable LogicFromTransform(Transform[ for (int i = 0; i < spring.joints.Length - 1; ++i) { var joint = spring.joints[i]; - Debug.Assert(i + 1 < spring.joints.Length); - var tailJoint = (i + 1 < spring.joints.Length) ? spring.joints[i + 1] : (FastSpringBoneJoint?)null; - Debug.Assert(tailJoint.HasValue); - var parentJoint = i - 1 >= 0 ? spring.joints[i - 1] : (FastSpringBoneJoint?)null; - Vector3 localPosition; - if (tailJoint.HasValue) - { - localPosition = tailJoint.Value.Transform.localPosition; - } - else - { - if (parentJoint.HasValue) - { - var delta = joint.Transform.position - parentJoint.Value.Transform.position; - localPosition = - joint.Transform.worldToLocalMatrix.MultiplyPoint(joint.Transform.position + delta); - } - else - { - localPosition = Vector3.down; - } - } + var tailJoint = spring.joints[i + 1]; + var localPosition = tailJoint.Transform.localPosition; - var scale = tailJoint.HasValue ? tailJoint.Value.Transform.lossyScale : joint.Transform.lossyScale; + var scale = tailJoint.Transform.lossyScale; var localChildPosition = new Vector3( localPosition.x * scale.x, localPosition.y * scale.y, localPosition.z * scale.z ); - var parent = joint.Transform.parent; yield return new BlittableJointImmutable { - headTransformIndex = Array.IndexOf(Transforms, joint.Transform), - parentTransformIndex = Array.IndexOf(Transforms, parent), - tailTransformIndex = Array.IndexOf(Transforms, tailJoint.Value), + headTransformIndex = Array.IndexOf(Transforms, joint.Transform), + parentTransformIndex = Array.IndexOf(Transforms, joint.Transform.parent), + tailTransformIndex = Array.IndexOf(Transforms, tailJoint.Transform), localRotation = joint.DefaultLocalRotation, boneAxis = localChildPosition.normalized, length = localChildPosition.magnitude diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs index 131bf0695f..68f5bdec66 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/ImporterContext.cs @@ -131,7 +131,12 @@ public virtual async Task LoadAsync(IAwaitCaller awaitCalle await OnLoadHierarchy(awaitCaller, MeasureTime); - return RuntimeGltfInstance.AttachTo(Root, this); + var instance = RuntimeGltfInstance.AttachTo(Root, this); + + // RuntimeGltfInstance を使う初期化(SpringBone) + await FinalizeAsync(awaitCaller); + + return instance; } public virtual async Task LoadAnimationAsync(IAwaitCaller awaitCaller) @@ -307,6 +312,12 @@ protected virtual Task OnLoadHierarchy(IAwaitCaller awaitCaller, Func(null); } + protected virtual Task FinalizeAsync(IAwaitCaller awaitCaller) + { + // do nothing + return Task.FromResult(null); + } + async Task BuildMeshAsync(IAwaitCaller awaitCaller, Func MeasureTime, MeshData meshData, int i) { using (MeasureTime("BuildMesh")) diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10FastSpringboneRuntime.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10FastSpringboneRuntime.cs index 11d70268c5..7c98dedfa1 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10FastSpringboneRuntime.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10FastSpringboneRuntime.cs @@ -94,13 +94,14 @@ public void RestoreInitialTransform() { // Spring の joint に対応する transform の回転を初期状態 var instance = m_instance.GetComponent(); - for (int i = 0; i < m_fastSpringBoneBuffer.Transforms.Length; ++i) + foreach (var logic in m_fastSpringBoneBuffer.Logics) { - var transform = m_fastSpringBoneBuffer.Transforms[i]; + var transform = m_fastSpringBoneBuffer.Transforms[logic.headTransformIndex]; transform.localRotation = instance.InitialTransformStates[transform].LocalRotation; } - // TODO: jobs のバッファにも反映する必要あり + // jobs のバッファにも反映する必要あり + m_fastSpringBoneService.BufferCombiner.InitializeJointsLocalRotation(m_fastSpringBoneBuffer); } public void Process() diff --git a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10FastSpringboneRuntimeStandalone.cs b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10FastSpringboneRuntimeStandalone.cs index 75d5e96756..43222561a2 100644 --- a/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10FastSpringboneRuntimeStandalone.cs +++ b/Assets/VRM10/Runtime/Components/Vrm10Runtime/Vrm10FastSpringboneRuntimeStandalone.cs @@ -103,13 +103,14 @@ public void RestoreInitialTransform() { // Spring の joint に対応する transform の回転を初期状態 var instance = m_instance.GetComponent(); - for (int i = 0; i < m_fastSpringBoneBuffer.Transforms.Length; ++i) + foreach (var logic in m_fastSpringBoneBuffer.Logics) { - var transform = m_fastSpringBoneBuffer.Transforms[i]; + var transform = m_fastSpringBoneBuffer.Transforms[logic.headTransformIndex]; transform.localRotation = instance.InitialTransformStates[transform].LocalRotation; } - // TODO: jobs のバッファにも反映する必要あり + // jobs のバッファにも反映する必要あり + m_bufferCombiner.InitializeJointsLocalRotation(m_fastSpringBoneBuffer); } public void Process() diff --git a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs index f458eff2ec..0543f9f6c3 100644 --- a/Assets/VRM10/Runtime/IO/Vrm10Importer.cs +++ b/Assets/VRM10/Runtime/IO/Vrm10Importer.cs @@ -249,6 +249,9 @@ protected override async Task LoadGeometryAsync(IAwaitCaller awaitCaller, Func + /// RuntimeGltfInstance 移譲するリソースの作成をする初期化 + /// protected override async Task OnLoadHierarchy(IAwaitCaller awaitCaller, Func MeasureTime) { Root.name = "VRM1"; @@ -268,22 +271,36 @@ protected override async Task OnLoadHierarchy(IAwaitCaller awaitCaller, Func + /// RuntimeGltfInstance アタッチよりあとの初期化 + /// + /// RuntimeGltfInstance.InitialTransformStates にアクセスするなど + /// + protected override async Task FinalizeAsync(IAwaitCaller awaitCaller) + { + var controller = Root.GetComponent(); // springBone if (UniGLTF.Extensions.VRMC_springBone.GltfDeserializer.TryGet(Data.GLTF.extensions, out UniGLTF.Extensions.VRMC_springBone.VRMC_springBone springBone)) { await LoadSpringBoneAsync(awaitCaller, controller, springBone); + if (Application.isPlaying) { // EditorImport では呼ばない // Vrm10Runtime で初期化していたが、 async にするためこちらに移動 v0.127 + // RuntimeGltfInstance にアクセスしたいのだが OnLoadHierarchy ではまだ attach されてなかった v0.128 await m_springboneRuntime.InitializeAsync(controller, awaitCaller); } } + // constraint await LoadConstraintAsync(awaitCaller, controller); // Hierarchyの構築が終わるまで遅延させる + // TODO: springbone の startup 問題なら、springbone はデフォルト pause 状態でいいかもしれない controller.enabled = true; }