mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-06-02 22:14:30 -05:00
Merge pull request #2453 from ousttrue/fix/fast_combinedbuffer
[1.0] SpringBone の reset 実装と関連する修正
This commit is contained in:
commit
521cfa0901
|
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// FastSpringBoneの処理に利用するバッファを全て結合して持つクラス
|
||||
/// CombinedBuffer 構築を管理する
|
||||
///
|
||||
/// - FastSpringBoneBuffer(Vrm-1.0 一体分の情報)を登録・削除する。
|
||||
/// - 再構築する。登録・削除後に反映するために呼び出す。
|
||||
/// - (TODO) FastSpringBoneBuffer一体分の回転初期化を実行する。
|
||||
///
|
||||
/// </summary>
|
||||
public sealed class FastSpringBoneBufferCombiner : IDisposable
|
||||
{
|
||||
// 長さと index 同じ
|
||||
private NativeArray<BlittableJointImmutable> _logics;
|
||||
private NativeArray<BlittableJointMutable> _joints;
|
||||
|
||||
private NativeArray<Vector3> _prevTails;
|
||||
private NativeArray<Vector3> _currentTails;
|
||||
private NativeArray<Vector3> _nextTails;
|
||||
|
||||
private NativeArray<BlittableSpring> _springs;
|
||||
|
||||
private NativeArray<BlittableCollider> _colliders;
|
||||
|
||||
private NativeArray<BlittableTransform> _transforms;
|
||||
private TransformAccessArray _transformAccessArray;
|
||||
|
||||
private FastSpringBoneCombinedBuffer _combinedBuffer;
|
||||
public FastSpringBoneCombinedBuffer Combined => _combinedBuffer;
|
||||
private readonly LinkedList<FastSpringBoneBuffer> _buffers = new LinkedList<FastSpringBoneBuffer>();
|
||||
private FastSpringBoneBuffer[] _batchedBuffers;
|
||||
private int[] _batchedBufferLogicSizes;
|
||||
|
||||
private bool _isDirty;
|
||||
|
||||
public NativeArray<BlittableJointImmutable> Logics => _logics;
|
||||
public NativeArray<BlittableJointMutable> Joints => _joints;
|
||||
public NativeArray<Vector3> PrevTails => _prevTails;
|
||||
public NativeArray<Vector3> CurrentTails => _currentTails;
|
||||
public NativeArray<Vector3> NextTails => _nextTails;
|
||||
|
||||
public NativeArray<BlittableSpring> Springs => _springs;
|
||||
|
||||
public NativeArray<BlittableCollider> Colliders => _colliders;
|
||||
|
||||
public NativeArray<BlittableTransform> 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 @@ namespace UniGLTF.SpringBoneJobs
|
|||
return handle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// バッチングされたバッファから、個々のバッファへと値を戻す
|
||||
/// バッファの再構築前にこの処理を行わないと、揺れの状態がリセットされてしまい、不自然な挙動になる
|
||||
/// </summary>
|
||||
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<BlittableJointImmutable>.Copy(_logics, logicsIndex, _batchedBuffers[i].Logics, 0, length);
|
||||
}
|
||||
|
||||
logicsIndex += length;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// バッファを再構築する
|
||||
/// </summary>
|
||||
|
|
@ -118,116 +56,19 @@ namespace UniGLTF.SpringBoneJobs
|
|||
{
|
||||
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)
|
||||
if (_combinedBuffer is FastSpringBoneCombinedBuffer combined)
|
||||
{
|
||||
springsCount += buffer.Springs.Length;
|
||||
collidersCount += buffer.Colliders.Length;
|
||||
logicsCount += buffer.Logics.Length;
|
||||
transformsCount += buffer.BlittableTransforms.Length;
|
||||
Profiler.BeginSample("FastSpringBone.ReconstructBuffers.SaveToSourceBuffer");
|
||||
combined.SaveToSourceBuffer();
|
||||
Profiler.EndSample();
|
||||
|
||||
// TODO: Dispose せずに再利用?
|
||||
combined.Dispose();
|
||||
}
|
||||
Profiler.EndSample();
|
||||
|
||||
// バッファの構築
|
||||
Profiler.BeginSample("FastSpringBone.ReconstructBuffers.CreateBuffers");
|
||||
|
||||
_logics = new NativeArray<BlittableJointImmutable>(logicsCount, Allocator.Persistent);
|
||||
_joints = new NativeArray<BlittableJointMutable>(logicsCount, Allocator.Persistent);
|
||||
_prevTails = new NativeArray<Vector3>(logicsCount, Allocator.Persistent);
|
||||
_currentTails = new NativeArray<Vector3>(logicsCount, Allocator.Persistent);
|
||||
_nextTails = new NativeArray<Vector3>(logicsCount, Allocator.Persistent);
|
||||
|
||||
_springs = new NativeArray<BlittableSpring>(springsCount, Allocator.Persistent);
|
||||
|
||||
_colliders = new NativeArray<BlittableCollider>(collidersCount, Allocator.Persistent);
|
||||
|
||||
_transforms = new NativeArray<BlittableTransform>(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++)
|
||||
{
|
||||
var buffer = _batchedBuffers[i];
|
||||
|
||||
// バッファの読み込みをスケジュール
|
||||
handle = new LoadTransformsJob
|
||||
{
|
||||
SrcTransforms = buffer.BlittableTransforms,
|
||||
DestTransforms = new NativeSlice<BlittableTransform>(_transforms, transformOffset,
|
||||
buffer.BlittableTransforms.Length)
|
||||
}.Schedule(buffer.BlittableTransforms.Length, 1, handle);
|
||||
|
||||
handle = new LoadSpringsJob
|
||||
{
|
||||
SrcSprings = buffer.Springs,
|
||||
DestSprings = new NativeSlice<BlittableSpring>(_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<BlittableCollider>(_colliders, collidersOffset, buffer.Colliders.Length)
|
||||
}.Schedule(buffer.Colliders.Length, 1, handle);
|
||||
|
||||
handle = new OffsetLogicsJob
|
||||
{
|
||||
SrcLogics = buffer.Logics,
|
||||
SrcJoints = buffer.Joints,
|
||||
|
||||
DestLogics = new NativeSlice<BlittableJointImmutable>(_logics, logicsOffset, buffer.Logics.Length),
|
||||
DestJoints = new NativeSlice<BlittableJointMutable>(_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[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();
|
||||
|
||||
|
|
@ -235,137 +76,22 @@ namespace UniGLTF.SpringBoneJobs
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transform から currentTail を更新。
|
||||
/// prevTail も同じ内容にする(速度0)。
|
||||
/// 各Jointのローカルローテーションを初期回転に戻す。spring reset
|
||||
/// </summary>
|
||||
/// <param name="handle"></param>
|
||||
/// <returns></returns>
|
||||
public JobHandle InitCurrentTails(JobHandle handle)
|
||||
public void InitializeJointsLocalRotation(FastSpringBoneBuffer model)
|
||||
{
|
||||
return new InitCurrentTailsJob
|
||||
if (_combinedBuffer is FastSpringBoneCombinedBuffer combined)
|
||||
{
|
||||
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();
|
||||
combined.InitializeJointsLocalRotation(model);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DisposeAllBuffers();
|
||||
}
|
||||
|
||||
#if ENABLE_SPRINGBONE_BURST
|
||||
[BurstCompile]
|
||||
#endif
|
||||
private struct LoadTransformsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<BlittableTransform> SrcTransforms;
|
||||
[WriteOnly] public NativeSlice<BlittableTransform> DestTransforms;
|
||||
|
||||
public void Execute(int index)
|
||||
if (_combinedBuffer is FastSpringBoneCombinedBuffer combined)
|
||||
{
|
||||
DestTransforms[index] = SrcTransforms[index];
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_SPRINGBONE_BURST
|
||||
[BurstCompile]
|
||||
#endif
|
||||
private struct LoadSpringsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<BlittableSpring> SrcSprings;
|
||||
[WriteOnly] public NativeSlice<BlittableSpring> 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<BlittableCollider> SrcColliders;
|
||||
[WriteOnly] public NativeSlice<BlittableCollider> DestColliders;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
DestColliders[index] = SrcColliders[index];
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_SPRINGBONE_BURST
|
||||
[BurstCompile]
|
||||
#endif
|
||||
private struct OffsetLogicsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeSlice<BlittableJointImmutable> SrcLogics;
|
||||
[ReadOnly] public NativeSlice<BlittableJointMutable> SrcJoints;
|
||||
[WriteOnly] public NativeSlice<BlittableJointImmutable> DestLogics;
|
||||
[WriteOnly] public NativeSlice<BlittableJointMutable> 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<BlittableJointImmutable> Logics;
|
||||
[ReadOnly] public NativeArray<BlittableTransform> Transforms;
|
||||
[WriteOnly] public NativeSlice<Vector3> CurrentTails;
|
||||
[WriteOnly] public NativeSlice<Vector3> PrevTails;
|
||||
[WriteOnly] public NativeSlice<Vector3> 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;
|
||||
}
|
||||
combined.Dispose();
|
||||
_combinedBuffer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,360 @@
|
|||
#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
|
||||
{
|
||||
/// <summary>
|
||||
/// FastSpringBoneの処理に利用するバッファを全て結合して持つクラス
|
||||
/// </summary>
|
||||
public class FastSpringBoneCombinedBuffer : IDisposable
|
||||
{
|
||||
// 長さと index 同じ
|
||||
private NativeArray<BlittableJointImmutable> _logics;
|
||||
private NativeArray<BlittableJointMutable> _joints;
|
||||
private NativeArray<Vector3> _prevTails;
|
||||
private NativeArray<Vector3> _currentTails;
|
||||
private NativeArray<Vector3> _nextTails;
|
||||
|
||||
private NativeArray<BlittableSpring> _springs;
|
||||
|
||||
private NativeArray<BlittableCollider> _colliders;
|
||||
|
||||
private NativeArray<BlittableTransform> _transforms;
|
||||
private TransformAccessArray _transformAccessArray;
|
||||
|
||||
public NativeArray<BlittableJointImmutable> Logics => _logics;
|
||||
public NativeArray<BlittableJointMutable> Joints => _joints;
|
||||
public NativeArray<Vector3> PrevTails => _prevTails;
|
||||
public NativeArray<Vector3> CurrentTails => _currentTails;
|
||||
public NativeArray<Vector3> NextTails => _nextTails;
|
||||
|
||||
public NativeArray<BlittableSpring> Springs => _springs;
|
||||
|
||||
public NativeArray<BlittableCollider> Colliders => _colliders;
|
||||
|
||||
public NativeArray<BlittableTransform> 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<BlittableJointImmutable>(logicsCount, Allocator.Persistent);
|
||||
_joints = new NativeArray<BlittableJointMutable>(logicsCount, Allocator.Persistent);
|
||||
_prevTails = new NativeArray<Vector3>(logicsCount, Allocator.Persistent);
|
||||
_currentTails = new NativeArray<Vector3>(logicsCount, Allocator.Persistent);
|
||||
_nextTails = new NativeArray<Vector3>(logicsCount, Allocator.Persistent);
|
||||
_springs = new NativeArray<BlittableSpring>(springsCount, Allocator.Persistent);
|
||||
_colliders = new NativeArray<BlittableCollider>(collidersCount, Allocator.Persistent);
|
||||
_transforms = new NativeArray<BlittableTransform>(transformsCount, Allocator.Persistent);
|
||||
_batchedBuffers = batchedBuffers;
|
||||
_batchedBufferLogicSizes = batchedBufferLogicSizes;
|
||||
}
|
||||
|
||||
internal static JobHandle Create(JobHandle handle,
|
||||
LinkedList<FastSpringBoneBuffer> _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<BlittableTransform>(_transforms, transformOffset,
|
||||
buffer.BlittableTransforms.Length)
|
||||
}.Schedule(buffer.BlittableTransforms.Length, 1, handle);
|
||||
|
||||
handle = new LoadSpringsJob
|
||||
{
|
||||
SrcSprings = buffer.Springs,
|
||||
DestSprings = new NativeSlice<BlittableSpring>(_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<BlittableCollider>(_colliders, collidersOffset, buffer.Colliders.Length)
|
||||
}.Schedule(buffer.Colliders.Length, 1, handle);
|
||||
|
||||
handle = new OffsetLogicsJob
|
||||
{
|
||||
SrcLogics = buffer.Logics,
|
||||
SrcJoints = buffer.Joints,
|
||||
|
||||
DestLogics = new NativeSlice<BlittableJointImmutable>(_logics, logicsOffset, buffer.Logics.Length),
|
||||
DestJoints = new NativeSlice<BlittableJointMutable>(_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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// バッチングされたバッファから、個々のバッファへと値を戻す
|
||||
/// Logics to _batchedBuffers[].Logics
|
||||
/// バッファの再構築前にこの処理を行わないと、揺れの状態がリセットされてしまい、不自然な挙動になる
|
||||
/// </summary>
|
||||
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<BlittableJointImmutable>.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
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private struct LoadTransformsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<BlittableTransform> SrcTransforms;
|
||||
[WriteOnly] public NativeSlice<BlittableTransform> DestTransforms;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
DestTransforms[index] = SrcTransforms[index];
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_SPRINGBONE_BURST
|
||||
[BurstCompile]
|
||||
#endif
|
||||
private struct LoadSpringsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeArray<BlittableSpring> SrcSprings;
|
||||
[WriteOnly] public NativeSlice<BlittableSpring> 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<BlittableCollider> SrcColliders;
|
||||
[WriteOnly] public NativeSlice<BlittableCollider> DestColliders;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
DestColliders[index] = SrcColliders[index];
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_SPRINGBONE_BURST
|
||||
[BurstCompile]
|
||||
#endif
|
||||
private struct OffsetLogicsJob : IJobParallelFor
|
||||
{
|
||||
[ReadOnly] public NativeSlice<BlittableJointImmutable> SrcLogics;
|
||||
[ReadOnly] public NativeSlice<BlittableJointMutable> SrcJoints;
|
||||
[WriteOnly] public NativeSlice<BlittableJointImmutable> DestLogics;
|
||||
[WriteOnly] public NativeSlice<BlittableJointMutable> 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<BlittableJointImmutable> Logics;
|
||||
[ReadOnly] public NativeArray<BlittableTransform> Transforms;
|
||||
[WriteOnly] public NativeSlice<Vector3> CurrentTails;
|
||||
[WriteOnly] public NativeSlice<Vector3> PrevTails;
|
||||
[WriteOnly] public NativeSlice<Vector3> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transform から currentTail を更新。
|
||||
/// prevTail も同じ内容にする(速度0)。
|
||||
/// </summary>
|
||||
/// <param name="handle"></param>
|
||||
/// <returns></returns>
|
||||
public JobHandle InitCurrentTails(JobHandle handle)
|
||||
{
|
||||
return new InitCurrentTailsJob
|
||||
{
|
||||
Logics = Logics,
|
||||
Transforms = Transforms,
|
||||
CurrentTails = CurrentTails,
|
||||
PrevTails = PrevTails,
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0485fe3392c9d0246bfb6b44720b8153
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -26,30 +26,33 @@ namespace UniGLTF.SpringBoneJobs
|
|||
return handle;
|
||||
}
|
||||
|
||||
handle = new PullTransformJob
|
||||
if (_bufferCombiner.Combined is FastSpringBoneCombinedBuffer combined)
|
||||
{
|
||||
Transforms = _bufferCombiner.Transforms
|
||||
}.Schedule(_bufferCombiner.TransformAccessArray, handle);
|
||||
handle = new PullTransformJob
|
||||
{
|
||||
Transforms = combined.Transforms
|
||||
}.Schedule(combined.TransformAccessArray, handle);
|
||||
|
||||
_bufferCombiner.FlipBuffer();
|
||||
combined.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 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 = _bufferCombiner.Transforms
|
||||
}.Schedule(_bufferCombiner.TransformAccessArray, handle);
|
||||
handle = new PushTransformJob
|
||||
{
|
||||
Transforms = combined.Transforms
|
||||
}.Schedule(combined.TransformAccessArray, handle);
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,42 +151,21 @@ namespace UniGLTF.SpringBoneJobs.InputPorts
|
|||
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<Transform>(Transforms, joint.Transform),
|
||||
parentTransformIndex = Array.IndexOf<Transform>(Transforms, joint.Transform.parent),
|
||||
tailTransformIndex = Array.IndexOf<Transform>(Transforms, tailJoint.Transform),
|
||||
localRotation = joint.DefaultLocalRotation,
|
||||
boneAxis = localChildPosition.normalized,
|
||||
length = localChildPosition.magnitude
|
||||
|
|
|
|||
|
|
@ -131,7 +131,12 @@ namespace UniGLTF
|
|||
|
||||
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 @@ namespace UniGLTF
|
|||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
protected virtual Task FinalizeAsync(IAwaitCaller awaitCaller)
|
||||
{
|
||||
// do nothing
|
||||
return Task.FromResult<object>(null);
|
||||
}
|
||||
|
||||
async Task<MeshWithMaterials> BuildMeshAsync(IAwaitCaller awaitCaller, Func<string, IDisposable> MeasureTime, MeshData meshData, int i)
|
||||
{
|
||||
using (MeasureTime("BuildMesh"))
|
||||
|
|
|
|||
|
|
@ -94,13 +94,14 @@ namespace UniVRM10
|
|||
{
|
||||
// Spring の joint に対応する transform の回転を初期状態
|
||||
var instance = m_instance.GetComponent<RuntimeGltfInstance>();
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -103,13 +103,14 @@ namespace UniVRM10
|
|||
{
|
||||
// Spring の joint に対応する transform の回転を初期状態
|
||||
var instance = m_instance.GetComponent<RuntimeGltfInstance>();
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -249,6 +249,9 @@ namespace UniVRM10
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RuntimeGltfInstance 移譲するリソースの作成をする初期化
|
||||
/// </summary>
|
||||
protected override async Task OnLoadHierarchy(IAwaitCaller awaitCaller, Func<string, IDisposable> MeasureTime)
|
||||
{
|
||||
Root.name = "VRM1";
|
||||
|
|
@ -268,22 +271,36 @@ namespace UniVRM10
|
|||
|
||||
// vrm
|
||||
controller.Vrm = await LoadVrmAsync(awaitCaller, m_vrm.VrmExtension);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RuntimeGltfInstance アタッチよりあとの初期化
|
||||
///
|
||||
/// RuntimeGltfInstance.InitialTransformStates にアクセスするなど
|
||||
/// </summary>
|
||||
protected override async Task FinalizeAsync(IAwaitCaller awaitCaller)
|
||||
{
|
||||
var controller = Root.GetComponent<Vrm10Instance>();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user