mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-08-27 05:14:27 -05:00
Merge pull request #1868 from notargs/external_force
SpringBoneに対して外力を渡すインターフェースを実装する
This commit is contained in:
@@ -27,6 +27,7 @@ namespace UniVRM10
|
||||
private readonly IReadOnlyDictionary<Transform, TransformState> m_defaultTransformStates;
|
||||
|
||||
private FastSpringBoneBuffer m_fastSpringBoneBuffer;
|
||||
private BlittableExternalData m_externalData;
|
||||
|
||||
/// <summary>
|
||||
/// Control Rig may be null.
|
||||
@@ -38,6 +39,16 @@ namespace UniVRM10
|
||||
public Vrm10RuntimeExpression Expression { get; }
|
||||
public Vrm10RuntimeLookAt LookAt { get; }
|
||||
|
||||
public Vector3 ExternalForce
|
||||
{
|
||||
get => m_externalData.ExternalForce;
|
||||
set
|
||||
{
|
||||
m_externalData.ExternalForce = value;
|
||||
m_fastSpringBoneBuffer.ExternalData = m_externalData;
|
||||
}
|
||||
}
|
||||
|
||||
public Vrm10Runtime(Vrm10Instance target, ControlRigGenerationOption controlRigGenerationOption)
|
||||
{
|
||||
m_target = target;
|
||||
@@ -131,7 +142,8 @@ namespace UniVRM10
|
||||
},
|
||||
DefaultLocalRotation = GetOrAddDefaultTransformState(joint.transform).LocalRotation,
|
||||
}).ToArray(),
|
||||
}).ToArray());
|
||||
}).ToArray(),
|
||||
m_externalData);
|
||||
}
|
||||
|
||||
private TransformState GetOrAddDefaultTransformState(Transform tf)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UniVRM10.FastSpringBones.Blittables
|
||||
{
|
||||
/// <summary>
|
||||
/// 外力等の毎フレーム更新されうる外部から与えられる情報
|
||||
/// </summary>
|
||||
public struct BlittableExternalData
|
||||
{
|
||||
public Vector3 ExternalForce;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a5066fc4e264010a58c19b781d477a0
|
||||
timeCreated: 1666166451
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace UniVRM10.FastSpringBones.Blittables
|
||||
{
|
||||
/// <summary>
|
||||
/// 1本の毛束を表すデータ型
|
||||
/// FastSpringBoneではこれを起点として並列化し、処理を行う
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct BlittableSpring
|
||||
@@ -13,5 +13,6 @@ namespace UniVRM10.FastSpringBones.Blittables
|
||||
public BlittableSpan logicSpan;
|
||||
public int centerTransformIndex;
|
||||
public int transformIndexOffset;
|
||||
public unsafe BlittableExternalData* ExternalData;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
using UniVRM10.FastSpringBones.Blittables;
|
||||
@@ -13,6 +14,7 @@ namespace UniVRM10.FastSpringBones.System
|
||||
/// </summary>
|
||||
public class FastSpringBoneBuffer : IDisposable
|
||||
{
|
||||
// NOTE: これらはFastSpringBoneBufferCombinerによってバッチングされる
|
||||
public NativeArray<BlittableSpring> Springs { get; }
|
||||
public NativeArray<BlittableJoint> Joints { get; }
|
||||
public NativeArray<BlittableCollider> Colliders { get; }
|
||||
@@ -21,10 +23,24 @@ namespace UniVRM10.FastSpringBones.System
|
||||
public Transform[] Transforms { get; }
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public FastSpringBoneBuffer(IReadOnlyList<FastSpringBoneSpring> springs, bool simulateLastBone = false)
|
||||
// NOTE: これは更新頻度が高くバッチングが難しいため、ランダムアクセスを許容してメモリへ直接アクセスする
|
||||
// 生のヒープ領域は扱いにくいので長さ1のNativeArrayで代用
|
||||
private NativeArray<BlittableExternalData> _externalData;
|
||||
|
||||
public BlittableExternalData ExternalData
|
||||
{
|
||||
get => _externalData[0];
|
||||
set => _externalData[0] = value;
|
||||
}
|
||||
|
||||
public unsafe FastSpringBoneBuffer(IReadOnlyList<FastSpringBoneSpring> springs,
|
||||
BlittableExternalData externalData,
|
||||
bool simulateLastBone = false)
|
||||
{
|
||||
Profiler.BeginSample("FastSpringBone.ConstructBuffers");
|
||||
|
||||
_externalData = new NativeArray<BlittableExternalData>(1, Allocator.Persistent);
|
||||
|
||||
// Transformの列挙
|
||||
Profiler.BeginSample("FastSpringBone.ConstructBuffers.ConstructTransformBuffer");
|
||||
var transformHashSet = new HashSet<Transform>();
|
||||
@@ -35,6 +51,7 @@ namespace UniVRM10.FastSpringBones.System
|
||||
transformHashSet.Add(joint.Transform);
|
||||
if (joint.Transform.parent != null) transformHashSet.Add(joint.Transform.parent);
|
||||
}
|
||||
|
||||
foreach (var collider in spring.colliders)
|
||||
{
|
||||
transformHashSet.Add(collider.Transform);
|
||||
@@ -42,6 +59,7 @@ namespace UniVRM10.FastSpringBones.System
|
||||
|
||||
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);
|
||||
@@ -68,7 +86,8 @@ namespace UniVRM10.FastSpringBones.System
|
||||
startIndex = blittableJoints.Count,
|
||||
count = simulateLastBone ? spring.joints.Length : spring.joints.Length - 1,
|
||||
},
|
||||
centerTransformIndex = spring.center ? transformIndexDictionary[spring.center] : -1
|
||||
centerTransformIndex = spring.center ? transformIndexDictionary[spring.center] : -1,
|
||||
ExternalData = (BlittableExternalData*) _externalData.GetUnsafePtr()
|
||||
};
|
||||
blittableSprings.Add(blittableSpring);
|
||||
|
||||
@@ -78,17 +97,18 @@ namespace UniVRM10.FastSpringBones.System
|
||||
blittable.transformIndex = transformIndexDictionary[collider.Transform];
|
||||
return blittable;
|
||||
}));
|
||||
blittableJoints.AddRange(spring.joints.Take(simulateLastBone ? spring.joints.Length : spring.joints.Length - 1).Select(joint =>
|
||||
{
|
||||
var blittable = joint.Joint;
|
||||
return blittable;
|
||||
}));
|
||||
blittableJoints.AddRange(spring.joints
|
||||
.Take(simulateLastBone ? spring.joints.Length : spring.joints.Length - 1).Select(joint =>
|
||||
{
|
||||
var blittable = joint.Joint;
|
||||
return blittable;
|
||||
}));
|
||||
|
||||
for (var i = 0; i < (simulateLastBone ? spring.joints.Length : spring.joints.Length - 1); ++i)
|
||||
{
|
||||
var joint = spring.joints[i];
|
||||
var tailJoint = i + 1 < spring.joints.Length ? spring.joints[i + 1] : (FastSpringBoneJoint?)null;
|
||||
var parentJoint = i - 1 >= 0 ? spring.joints[i - 1] : (FastSpringBoneJoint?)null;
|
||||
var tailJoint = i + 1 < spring.joints.Length ? spring.joints[i + 1] : (FastSpringBoneJoint?) null;
|
||||
var parentJoint = i - 1 >= 0 ? spring.joints[i - 1] : (FastSpringBoneJoint?) null;
|
||||
var localPosition = Vector3.zero;
|
||||
if (tailJoint.HasValue)
|
||||
{
|
||||
@@ -99,13 +119,15 @@ namespace UniVRM10.FastSpringBones.System
|
||||
if (parentJoint.HasValue)
|
||||
{
|
||||
var delta = joint.Transform.position - parentJoint.Value.Transform.position;
|
||||
localPosition = joint.Transform.worldToLocalMatrix.MultiplyPoint(joint.Transform.position + delta);
|
||||
localPosition =
|
||||
joint.Transform.worldToLocalMatrix.MultiplyPoint(joint.Transform.position + delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
localPosition = Vector3.down;
|
||||
}
|
||||
}
|
||||
|
||||
var scale = tailJoint.HasValue ? tailJoint.Value.Transform.lossyScale : joint.Transform.lossyScale;
|
||||
var localChildPosition =
|
||||
new Vector3(
|
||||
@@ -131,6 +153,7 @@ namespace UniVRM10.FastSpringBones.System
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
// 各種bufferの初期化
|
||||
@@ -157,6 +180,7 @@ namespace UniVRM10.FastSpringBones.System
|
||||
BlittableTransforms.Dispose();
|
||||
Colliders.Dispose();
|
||||
Logics.Dispose();
|
||||
_externalData.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,8 @@ namespace UniVRM10.FastSpringBones.System
|
||||
public NativeArray<BlittableCollider> Colliders => _colliders;
|
||||
public NativeArray<BlittableLogic> Logics => _logics;
|
||||
|
||||
public bool HasBuffer => _batchedBuffers != null && _batchedBuffers.Length > 0;
|
||||
|
||||
public void Register(FastSpringBoneBuffer buffer)
|
||||
{
|
||||
_buffers.AddLast(buffer);
|
||||
@@ -81,6 +83,7 @@ namespace UniVRM10.FastSpringBones.System
|
||||
{
|
||||
NativeArray<BlittableLogic>.Copy(_logics, logicsIndex, _batchedBuffers[i].Logics, 0, length);
|
||||
}
|
||||
|
||||
logicsIndex += length;
|
||||
}
|
||||
}
|
||||
@@ -107,7 +110,7 @@ namespace UniVRM10.FastSpringBones.System
|
||||
|
||||
Profiler.BeginSample("FastSpringBone.ReconstructBuffers.CopyToBatchedBuffers");
|
||||
_batchedBuffers = _buffers.ToArray();
|
||||
_batchedBufferLogicSizes = _buffers.Select(buffer => buffer.Logics.Length).ToArray();
|
||||
_batchedBufferLogicSizes = _batchedBuffers.Select(buffer => buffer.Logics.Length).ToArray();
|
||||
Profiler.EndSample();
|
||||
|
||||
// バッファを数える
|
||||
@@ -139,8 +142,10 @@ namespace UniVRM10.FastSpringBones.System
|
||||
var transformOffset = 0;
|
||||
|
||||
Profiler.BeginSample("FastSpringBone.ReconstructBuffers.ScheduleLoadBufferJobs");
|
||||
foreach (var buffer in _buffers)
|
||||
for (var i = 0; i < _batchedBuffers.Length; i++)
|
||||
{
|
||||
var buffer = _batchedBuffers[i];
|
||||
|
||||
// バッファの読み込みをスケジュール
|
||||
handle = new LoadTransformsJob
|
||||
{
|
||||
@@ -155,15 +160,15 @@ namespace UniVRM10.FastSpringBones.System
|
||||
DestSprings = new NativeSlice<BlittableSpring>(_springs, springsOffset, buffer.Springs.Length),
|
||||
CollidersOffset = collidersOffset,
|
||||
LogicsOffset = logicsOffset,
|
||||
TransformOffset = transformOffset
|
||||
TransformOffset = transformOffset,
|
||||
}.Schedule(buffer.Springs.Length, 1, handle);
|
||||
handle = new LoadCollidersJob()
|
||||
handle = new LoadCollidersJob
|
||||
{
|
||||
SrcColliders = buffer.Colliders,
|
||||
DestColliders =
|
||||
new NativeSlice<BlittableCollider>(_colliders, collidersOffset, buffer.Colliders.Length)
|
||||
}.Schedule(buffer.Colliders.Length, 1, handle);
|
||||
handle = new OffsetLogicsJob()
|
||||
handle = new OffsetLogicsJob
|
||||
{
|
||||
SrcLogics = buffer.Logics,
|
||||
SrcJoints = buffer.Joints,
|
||||
@@ -185,7 +190,7 @@ namespace UniVRM10.FastSpringBones.System
|
||||
Profiler.BeginSample("FastSpringBone.ReconstructBuffers.LoadTransformAccessArray");
|
||||
var transforms = new Transform[transformsCount];
|
||||
var transformAccessArrayOffset = 0;
|
||||
foreach (var buffer in _buffers)
|
||||
foreach (var buffer in _batchedBuffers)
|
||||
{
|
||||
Array.Copy(buffer.Transforms, 0, transforms, transformAccessArrayOffset, buffer.Transforms.Length);
|
||||
transformAccessArrayOffset += buffer.BlittableTransforms.Length;
|
||||
@@ -260,7 +265,7 @@ namespace UniVRM10.FastSpringBones.System
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
DestColliders[index] = SrcColliders[index];
|
||||
DestColliders[index] = SrcColliders[index];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,4 +286,4 @@ namespace UniVRM10.FastSpringBones.System
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ namespace UniVRM10.FastSpringBones.System
|
||||
public sealed class FastSpringBoneScheduler : IDisposable
|
||||
{
|
||||
private readonly FastSpringBoneBufferCombiner _bufferCombiner;
|
||||
|
||||
public FastSpringBoneScheduler(FastSpringBoneBufferCombiner bufferCombiner)
|
||||
{
|
||||
_bufferCombiner = bufferCombiner;
|
||||
@@ -18,6 +17,10 @@ namespace UniVRM10.FastSpringBones.System
|
||||
{
|
||||
var handle = default(JobHandle);
|
||||
handle = _bufferCombiner.ReconstructIfDirty(handle);
|
||||
if (!_bufferCombiner.HasBuffer)
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
|
||||
handle = new PullTransformJob
|
||||
{
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace UniVRM10.FastSpringBones.System
|
||||
[NativeDisableParallelForRestriction] public NativeArray<BlittableTransform> Transforms;
|
||||
|
||||
public float DeltaTime;
|
||||
|
||||
public void Execute(int index)
|
||||
|
||||
public unsafe void Execute(int index)
|
||||
{
|
||||
var spring = Springs[index];
|
||||
var transformIndexOffset = spring.transformIndexOffset;
|
||||
@@ -43,7 +43,6 @@ namespace UniVRM10.FastSpringBones.System
|
||||
? Transforms[spring.centerTransformIndex + transformIndexOffset]
|
||||
: (BlittableTransform?)null;
|
||||
|
||||
|
||||
// 親があったら、親に依存するTransformを再計算
|
||||
if (parentTransform.HasValue)
|
||||
{
|
||||
@@ -62,7 +61,7 @@ namespace UniVRM10.FastSpringBones.System
|
||||
var parentRotation = parentTransform?.rotation ?? Quaternion.identity;
|
||||
|
||||
// verlet積分で次の位置を計算
|
||||
var external = joint.gravityDir * joint.gravityPower * DeltaTime;
|
||||
var external = (joint.gravityDir * joint.gravityPower + spring.ExternalData->ExternalForce) * DeltaTime;
|
||||
var nextTail = currentTail
|
||||
+ (currentTail - prevTail) * (1.0f - joint.dragForce) // 前フレームの移動を継続する(減衰もあるよ)
|
||||
+ parentRotation * logic.localRotation * logic.boneAxis *
|
||||
|
||||
Reference in New Issue
Block a user