FastSpringBoneBufferBuilder を FastSpringBoneBuffer.FastSpringBoneBuffer に合体

This commit is contained in:
ousttrue 2024-07-18 13:42:02 +09:00
parent 80c2bb921c
commit 7f089f1dd8
4 changed files with 155 additions and 194 deletions

View File

@ -14,8 +14,8 @@ namespace UniVRM10
private readonly Vrm10Instance m_instance;
private readonly IReadOnlyDictionary<Transform, TransformState> m_defaultTransformStates;
private readonly FastSpringBoneService m_fastSpringBoneService;
private FastSpringBoneBufferBuilder m_initialData;
private FastSpringBoneSpring[] m_springs;
private Quaternion[] m_initialLocalRotations;
private FastSpringBoneBuffer m_fastSpringBoneBuffer;
public Vector3 ExternalForce
{
@ -73,7 +73,7 @@ namespace UniVRM10
}
// create
var springs = m_instance.SpringBone.Springs.Select(spring => new FastSpringBoneSpring
m_springs = m_instance.SpringBone.Springs.Select(spring => new FastSpringBoneSpring
{
center = spring.Center,
colliders = spring.ColliderGroups
@ -105,9 +105,9 @@ namespace UniVRM10
}).ToArray(),
}).ToArray();
m_initialData = new FastSpringBoneBufferBuilder(springs);
m_fastSpringBoneBuffer = new FastSpringBoneBuffer(m_initialData);
m_fastSpringBoneBuffer = new FastSpringBoneBuffer(m_springs);
m_fastSpringBoneService.BufferCombiner.Register(m_fastSpringBoneBuffer);
m_initialLocalRotations = m_fastSpringBoneBuffer.Transforms.Select(x => x.localRotation).ToArray();
}
private TransformState GetOrAddDefaultTransformState(Transform tf)
@ -143,21 +143,21 @@ namespace UniVRM10
public void RestoreInitialTransform()
{
// Spring の joint に対応する transform の回転を初期状態
for (int i = 0; i < m_initialData.Transforms.Length; ++i)
for (int i = 0; i < m_fastSpringBoneBuffer.Transforms.Length; ++i)
{
var transform = m_initialData.Transforms[i];
transform.localRotation = m_initialData.InitialLocalRotations[i];
var transform = m_fastSpringBoneBuffer.Transforms[i];
transform.localRotation = m_initialLocalRotations[i];
}
// 初期状態にしたtransformを使って spring logic を構築
m_initialData.BlittableLogics.Clear();
foreach (var spring in m_initialData.Springs)
List<BlittableLogic> blittableLogics = new();
foreach (var spring in m_springs)
{
m_initialData.AddLogic(spring);
FastSpringBoneBuffer.AddLogic(m_fastSpringBoneBuffer.Transforms, blittableLogics, spring);
}
// DOTS バッファーを更新
m_initialData.SyncAndZeroVelocity(m_fastSpringBoneBuffer.Logics);
m_fastSpringBoneBuffer.SyncAndZeroVelocity(blittableLogics);
}
}
}

View File

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
@ -47,28 +49,148 @@ namespace UniVRM10.FastSpringBones.System
IsSpringBoneEnabled = value,
};
}
}
public unsafe FastSpringBoneBuffer(FastSpringBoneBufferBuilder b)
/// <summary>
/// Joint, Collider, Center の Transform のリスト
/// - 重複を除去
/// </summary>
/// <param name="springs"></param>
/// <returns></returns>
static Transform[] MakeFlattenTransformList(FastSpringBoneSpring[] springs)
{
Profiler.BeginSample("FastSpringBone.ConstructBuffers.ConstructNativeArrays");
var transformHashSet = new HashSet<Transform>();
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();
return Transforms;
}
public unsafe FastSpringBoneBuffer(FastSpringBoneSpring[] springs)
{
Profiler.BeginSample("FastSpringBone.ConstructBuffers.BufferBuilder");
Transforms = MakeFlattenTransformList(springs);
_externalData = new NativeArray<BlittableExternalData>(1, Allocator.Persistent);
_externalData[0] = new BlittableExternalData
{
ExternalForce = Vector3.zero,
IsSpringBoneEnabled = true,
};
b.SetExternalDataPtr((BlittableExternalData*)_externalData.GetUnsafePtr());
Springs = new NativeArray<BlittableSpring>(b.BlittableSprings.ToArray(), Allocator.Persistent);
Joints = new NativeArray<BlittableJoint>(b.BlittableJoints.ToArray(), Allocator.Persistent);
Colliders = new NativeArray<BlittableCollider>(b.BlittableColliders.ToArray(), Allocator.Persistent);
Logics = new NativeArray<BlittableLogic>(b.BlittableLogics.ToArray(), Allocator.Persistent);
BlittableTransforms = new NativeArray<BlittableTransform>(b.Transforms.Length, Allocator.Persistent);
Transforms = b.Transforms;
var externalDataPtr = (BlittableExternalData*)_externalData.GetUnsafePtr();
List<BlittableSpring> blittableSprings = new();
List<BlittableJoint> blittableJoints = new();
List<BlittableCollider> blittableColliders = new();
List<BlittableLogic> blittableLogics = new();
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 = Array.IndexOf(Transforms, spring.center),
ExternalData = externalDataPtr,
};
blittableSprings.Add(blittableSpring);
blittableColliders.AddRange(spring.colliders.Select(collider =>
{
var blittable = collider.Collider;
blittable.transformIndex = Array.IndexOf(Transforms, collider.Transform);
return blittable;
}));
blittableJoints.AddRange(spring.joints
.Take(spring.joints.Length - 1).Select(joint =>
{
var blittable = joint.Joint;
return blittable;
}));
AddLogic(Transforms, blittableLogics, spring);
}
Springs = new NativeArray<BlittableSpring>(blittableSprings.ToArray(), Allocator.Persistent);
Joints = new NativeArray<BlittableJoint>(blittableJoints.ToArray(), Allocator.Persistent);
Colliders = new NativeArray<BlittableCollider>(blittableColliders.ToArray(), Allocator.Persistent);
Logics = new NativeArray<BlittableLogic>(blittableLogics.ToArray(), Allocator.Persistent);
BlittableTransforms = new NativeArray<BlittableTransform>(Transforms.Length, Allocator.Persistent);
Profiler.EndSample();
}
static public void AddLogic(Transform[] Transforms, List<BlittableLogic> BlittableLogics, FastSpringBoneSpring spring)
{
for (var i = 0; i < 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 localPosition = Vector3.zero;
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 scale = tailJoint.HasValue ? tailJoint.Value.Transform.lossyScale : joint.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 = Array.IndexOf(Transforms, joint.Transform),
parentTransformIndex = Array.IndexOf(Transforms, parent),
currentTail = currentTail,
prevTail = currentTail,
localRotation = joint.DefaultLocalRotation,
boneAxis = localChildPosition.normalized,
length = localChildPosition.magnitude
});
}
}
public void Dispose()
{
if (IsDisposed) return;
@ -80,5 +202,16 @@ namespace UniVRM10.FastSpringBones.System
Logics.Dispose();
_externalData.Dispose();
}
public unsafe void SyncAndZeroVelocity(IReadOnlyList<BlittableLogic> logics)
{
var dst = Logics;
for (int i = 0; i < logics.Count; ++i)
{
var l = logics[i];
l.prevTail = l.currentTail;
dst[i] = l;
}
}
}
}

View File

@ -1,161 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Profiling;
using UniVRM10.FastSpringBones.Blittables;
namespace UniVRM10.FastSpringBones.System
{
public class FastSpringBoneBufferBuilder
{
public readonly List<BlittableSpring> BlittableSprings = new();
public readonly List<BlittableJoint> BlittableJoints = new();
public readonly List<BlittableCollider> BlittableColliders = new();
public readonly List<BlittableLogic> BlittableLogics = new();
public readonly Transform[] Transforms;
public readonly Quaternion[] InitialLocalRotations;
public struct TransformInfo
{
public int Index;
public Quaternion InitialLocalRotation;
}
public readonly FastSpringBoneSpring[] Springs;
public FastSpringBoneBufferBuilder(FastSpringBoneSpring[] springs)
{
Springs = springs;
Profiler.BeginSample("FastSpringBone.ConstructBuffers.BufferBuilder");
var transformHashSet = new HashSet<Transform>();
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);
}
Transforms = transformHashSet.ToArray();
InitialLocalRotations = Transforms.Select(x => x.localRotation).ToArray();
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 = Array.IndexOf(Transforms, spring.center),
};
BlittableSprings.Add(blittableSpring);
BlittableColliders.AddRange(spring.colliders.Select(collider =>
{
var blittable = collider.Collider;
blittable.transformIndex = Array.IndexOf(Transforms, collider.Transform);
return blittable;
}));
BlittableJoints.AddRange(spring.joints
.Take(spring.joints.Length - 1).Select(joint =>
{
var blittable = joint.Joint;
return blittable;
}));
AddLogic(spring);
}
Profiler.EndSample();
}
public void AddLogic(FastSpringBoneSpring spring)
{
for (var i = 0; i < 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 localPosition = Vector3.zero;
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 scale = tailJoint.HasValue ? tailJoint.Value.Transform.lossyScale : joint.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 = Array.IndexOf(Transforms, joint.Transform),
parentTransformIndex = Array.IndexOf(Transforms, parent),
currentTail = currentTail,
prevTail = currentTail,
localRotation = joint.DefaultLocalRotation,
boneAxis = localChildPosition.normalized,
length = localChildPosition.magnitude
});
}
}
public unsafe void SetExternalDataPtr(BlittableExternalData* externalData)
{
for (int i = 0; i < BlittableSprings.Count; ++i)
{
// blittableSprings[i] = blittableSprings[i] with
// {
// ExternalData = externalData,
// };
var b = BlittableSprings[i];
b.ExternalData = externalData;
BlittableSprings[i] = b;
}
}
public unsafe void SyncAndZeroVelocity(NativeArray<BlittableLogic> logics)
{
for (int i = 0; i < BlittableLogics.Count; ++i)
{
var l = BlittableLogics[i];
l.prevTail = l.currentTail;
logics[i] = BlittableLogics[i];
}
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 82dbc85cfa7168546b209a51f6342d84
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: