Skip to content

Commit

Permalink
IVrm10SpringBoneRuntime.InitializeAsync
Browse files Browse the repository at this point in the history
  • Loading branch information
ousttrue committed Sep 24, 2024
1 parent 9e5d11b commit 0b08507
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 156 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ internal Vrm10Runtime MakeRuntime(bool useControlRig)
// deafult に fallback
// TODO: scene に配置した prefab に SpringRuntime をカスタムする手段
m_springBoneRuntime = new Vrm10FastSpringboneRuntime();
m_springBoneRuntime.InitializeAsync(this, new ImmediateCaller());
}
return new Vrm10Runtime(this, useControlRig, m_springBoneRuntime);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using UniGLTF;
using UniGLTF.SpringBoneJobs.Blittables;
using UniGLTF.SpringBoneJobs.InputPorts;
using UniGLTF.Utils;
using UnityEngine;

namespace UniVRM10
{
public static class FastSpringBoneBufferFactory
{
/// <summary>
/// このVRMに紐づくSpringBone関連のバッファを構築する。
/// </summary>
/// <param name="awaitCaller"></param>
/// <param name="fastSpringBoneBuffer">TODO: 再利用する</param>
/// <returns></returns>
public static async Task<FastSpringBoneBuffer> ConstructSpringBoneAsync(IAwaitCaller awaitCaller, Vrm10Instance vrm,
FastSpringBoneBuffer fastSpringBoneBuffer = null)
{
// TODO: Dispose せずに再利用する最適化
// new FastSpringBoneBuffer にも構築ロジックがあるので合体して整理する必要あり。
// GC 軽減と await 挟み込み
if (fastSpringBoneBuffer != null)
{
fastSpringBoneBuffer.Dispose();
}

Func<Transform, TransformState> GetOrAddDefaultTransformState = (Transform tf) =>
{
if (vrm.DefaultTransformStates.TryGetValue(tf, out var defaultTransformState))
{
return defaultTransformState;
}
Debug.LogWarning($"{tf.name} does not exist on load.");
return new TransformState(null);
};

// create(Spring情報の再収集。設定変更の反映)
var springs = vrm.SpringBone.Springs.Select(spring => new FastSpringBoneSpring
{
center = spring.Center,
colliders = spring.ColliderGroups
.SelectMany(group => group.Colliders)
.Select(collider => new FastSpringBoneCollider
{
Transform = collider.transform,
Collider = new BlittableCollider
{
offset = collider.Offset,
radius = collider.Radius,
tailOrNormal = collider.TailOrNormal,
colliderType = TranslateColliderType(collider.ColliderType)
}
}).ToArray(),
joints = spring.Joints
.Select(joint => new FastSpringBoneJoint
{
Transform = joint.transform,
Joint = new BlittableJointMutable
{
radius = joint.m_jointRadius,
dragForce = joint.m_dragForce,
gravityDir = joint.m_gravityDir,
gravityPower = joint.m_gravityPower,
stiffnessForce = joint.m_stiffnessForce
},
DefaultLocalRotation = GetOrAddDefaultTransformState(joint.transform).LocalRotation,
}).ToArray(),
}).ToArray();

await awaitCaller.NextFrame();

fastSpringBoneBuffer = new FastSpringBoneBuffer(springs);
return fastSpringBoneBuffer;
}

private static BlittableColliderType TranslateColliderType(VRM10SpringBoneColliderTypes colliderType)
{
switch (colliderType)
{
case VRM10SpringBoneColliderTypes.Sphere:
return BlittableColliderType.Sphere;
case VRM10SpringBoneColliderTypes.Capsule:
return BlittableColliderType.Capsule;
case VRM10SpringBoneColliderTypes.Plane:
return BlittableColliderType.Plane;
case VRM10SpringBoneColliderTypes.SphereInside:
return BlittableColliderType.SphereInside;
case VRM10SpringBoneColliderTypes.CapsuleInside:
return BlittableColliderType.CapsuleInside;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
using System;
using System.Linq;
using UniGLTF;
using UniGLTF.Utils;
using UnityEngine;
using UniGLTF.SpringBoneJobs.Blittables;
using UniGLTF.SpringBoneJobs.InputPorts;
using System.Threading.Tasks;

namespace UniVRM10
{
Expand All @@ -17,9 +15,12 @@ public class Vrm10FastSpringboneRuntime : IVrm10SpringBoneRuntime
{
private Vrm10Instance m_instance;
private readonly FastSpringBones.FastSpringBoneService m_fastSpringBoneService = FastSpringBones.FastSpringBoneService.Instance;
private FastSpringBoneSpring[] m_springs;
private Quaternion[] m_initialLocalRotations;
private FastSpringBoneBuffer m_fastSpringBoneBuffer;
/// <summary>
/// 多重実行防止
/// </summary>
private bool m_building = false;

public Vector3 ExternalForce
{
get => m_fastSpringBoneBuffer.ExternalForce;
Expand All @@ -33,15 +34,16 @@ public bool IsSpringBoneEnabled

public float DeltaTime => throw new NotImplementedException();

/// <param name="initialTransform">VRMの初期姿勢(T-Pose)状態。instanceがT-Poseから変化していても大丈夫</param>
public void Initialize(Vrm10Instance instance)
public async Task InitializeAsync(Vrm10Instance instance, IAwaitCaller awaitCaller)
{
m_instance = instance;

// NOTE: FastSpringBoneService は UnitTest などでは動作しない
if (Application.isPlaying)
{
ReconstructSpringBone();
m_fastSpringBoneBuffer = await FastSpringBoneBufferFactory.ConstructSpringBoneAsync(awaitCaller, m_instance);
// 登録
m_fastSpringBoneService.BufferCombiner.Register(m_fastSpringBoneBuffer);
}
}

Expand All @@ -57,93 +59,40 @@ public void Dispose()
/// </summary>
public void ReconstructSpringBone()
{
// release
if (m_fastSpringBoneBuffer != null)
if (m_building)
{
m_fastSpringBoneService.BufferCombiner.Unregister(m_fastSpringBoneBuffer);
m_fastSpringBoneBuffer.Dispose();
Debug.LogWarning("already building");
return;
}
m_building = true;

// create(Spring情報の再収集。設定変更の反映)
m_springs = m_instance.SpringBone.Springs.Select(spring => new FastSpringBoneSpring
{
center = spring.Center,
colliders = spring.ColliderGroups
.SelectMany(group => group.Colliders)
.Select(collider => new FastSpringBoneCollider
{
Transform = collider.transform,
Collider = new BlittableCollider
{
offset = collider.Offset,
radius = collider.Radius,
tailOrNormal = collider.TailOrNormal,
colliderType = TranslateColliderType(collider.ColliderType)
}
}).ToArray(),
joints = spring.Joints
.Select(joint => new FastSpringBoneJoint
{
Transform = joint.transform,
Joint = new BlittableJointMutable
{
radius = joint.m_jointRadius,
dragForce = joint.m_dragForce,
gravityDir = joint.m_gravityDir,
gravityPower = joint.m_gravityPower,
stiffnessForce = joint.m_stiffnessForce
},
DefaultLocalRotation = GetOrAddDefaultTransformState(joint.transform).LocalRotation,
}).ToArray(),
}).ToArray();

// DOTS buffer 構築
m_fastSpringBoneBuffer = new FastSpringBoneBuffer(m_springs);
m_fastSpringBoneService.BufferCombiner.Register(m_fastSpringBoneBuffer);
// reset 用の初期状態の記録
m_initialLocalRotations = m_fastSpringBoneBuffer.Transforms.Select(x => x.localRotation).ToArray();
}

private TransformState GetOrAddDefaultTransformState(Transform tf)
{
if (m_instance.DefaultTransformStates.TryGetValue(tf, out var defaultTransformState))
// 登録削除
if (m_fastSpringBoneBuffer != null)
{
return defaultTransformState;
m_fastSpringBoneService.BufferCombiner.Unregister(m_fastSpringBoneBuffer);
}

Debug.LogWarning($"{tf.name} does not exist on load.");
return new TransformState(null);
}
// new ImmediateCaller() により即時実行して結果を得る。
// スパイクは許容する。
var task = FastSpringBoneBufferFactory.ConstructSpringBoneAsync(new ImmediateCaller(), m_instance, m_fastSpringBoneBuffer);
m_fastSpringBoneBuffer = task.Result;

private static BlittableColliderType TranslateColliderType(VRM10SpringBoneColliderTypes colliderType)
{
switch (colliderType)
{
case VRM10SpringBoneColliderTypes.Sphere:
return BlittableColliderType.Sphere;
case VRM10SpringBoneColliderTypes.Capsule:
return BlittableColliderType.Capsule;
case VRM10SpringBoneColliderTypes.Plane:
return BlittableColliderType.Plane;
case VRM10SpringBoneColliderTypes.SphereInside:
return BlittableColliderType.SphereInside;
case VRM10SpringBoneColliderTypes.CapsuleInside:
return BlittableColliderType.CapsuleInside;
default:
throw new ArgumentOutOfRangeException();
}
// 登録
m_fastSpringBoneService.BufferCombiner.Register(m_fastSpringBoneBuffer);
m_building = false;
}

public void RestoreInitialTransform()
{
// Spring の joint に対応する transform の回転を初期状態
var instance = m_instance.GetComponent<RuntimeGltfInstance>();
for (int i = 0; i < m_fastSpringBoneBuffer.Transforms.Length; ++i)
{
var transform = m_fastSpringBoneBuffer.Transforms[i];
transform.localRotation = m_initialLocalRotations[i];
transform.localRotation = instance.InitialTransformStates[transform].LocalRotation;
}

// TODO:
// TODO: jobs のバッファにも反映する必要あり
}

public void Process()
Expand Down
Loading

0 comments on commit 0b08507

Please sign in to comment.