mirror of
https://github.com/vrm-c/UniVRM.git
synced 2026-09-12 13:59:21 -05:00
separate FastSpringBoneBufferBuilder
This commit is contained in:
@@ -14,27 +14,17 @@ namespace UniVRM10
|
||||
private readonly Vrm10Instance m_instance;
|
||||
private readonly IReadOnlyDictionary<Transform, TransformState> m_defaultTransformStates;
|
||||
private readonly FastSpringBoneService m_fastSpringBoneService;
|
||||
private FastSpringBoneBuffer m_fastSpringBoneBuffer;
|
||||
private BlittableExternalData m_externalData;
|
||||
|
||||
private FastSpringBoneBuffer m_fastSpringBoneBuffer;
|
||||
public Vector3 ExternalForce
|
||||
{
|
||||
get => m_externalData.ExternalForce;
|
||||
set
|
||||
{
|
||||
m_externalData.ExternalForce = value;
|
||||
m_fastSpringBoneBuffer.ExternalData = m_externalData;
|
||||
}
|
||||
get => m_fastSpringBoneBuffer.ExternalForce;
|
||||
set { m_fastSpringBoneBuffer.ExternalForce = value; }
|
||||
}
|
||||
|
||||
public bool IsSpringBoneEnabled
|
||||
{
|
||||
get => m_externalData.IsSpringBoneEnabled;
|
||||
set
|
||||
{
|
||||
m_externalData.IsSpringBoneEnabled = value;
|
||||
m_fastSpringBoneBuffer.ExternalData = m_externalData;
|
||||
}
|
||||
get => m_fastSpringBoneBuffer.IsSpringBoneEnabled;
|
||||
set { m_fastSpringBoneBuffer.IsSpringBoneEnabled = value; }
|
||||
}
|
||||
|
||||
public Vrm10RuntimeSpringBone(Vrm10Instance instance)
|
||||
@@ -86,39 +76,39 @@ namespace UniVRM10
|
||||
|
||||
private FastSpringBoneBuffer CreateFastSpringBoneBuffer(Vrm10InstanceSpringBone springBone)
|
||||
{
|
||||
return new FastSpringBoneBuffer(
|
||||
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 BlittableJoint
|
||||
{
|
||||
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(),
|
||||
m_externalData);
|
||||
var b = new FastSpringBoneBufferBuilder(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 BlittableJoint
|
||||
{
|
||||
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(),
|
||||
}));
|
||||
|
||||
return new FastSpringBoneBuffer(b);
|
||||
}
|
||||
|
||||
private TransformState GetOrAddDefaultTransformState(Transform tf)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
@@ -26,149 +24,48 @@ namespace UniVRM10.FastSpringBones.System
|
||||
// NOTE: これは更新頻度が高くバッチングが難しいため、ランダムアクセスを許容してメモリへ直接アクセスする
|
||||
// 生のヒープ領域は扱いにくいので長さ1のNativeArrayで代用
|
||||
private NativeArray<BlittableExternalData> _externalData;
|
||||
|
||||
public BlittableExternalData ExternalData
|
||||
public Vector3 ExternalForce
|
||||
{
|
||||
get => _externalData[0];
|
||||
set => _externalData[0] = value;
|
||||
get => _externalData[0].ExternalForce;
|
||||
set
|
||||
{
|
||||
_externalData[0] = new BlittableExternalData
|
||||
{
|
||||
ExternalForce = value,
|
||||
IsSpringBoneEnabled = _externalData[0].IsSpringBoneEnabled,
|
||||
};
|
||||
}
|
||||
}
|
||||
public bool IsSpringBoneEnabled
|
||||
{
|
||||
get => _externalData[0].IsSpringBoneEnabled;
|
||||
set
|
||||
{
|
||||
_externalData[0] = new BlittableExternalData
|
||||
{
|
||||
ExternalForce = _externalData[0].ExternalForce,
|
||||
IsSpringBoneEnabled = value,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public unsafe FastSpringBoneBuffer(IReadOnlyList<FastSpringBoneSpring> springs,
|
||||
BlittableExternalData externalData,
|
||||
bool simulateLastBone = false)
|
||||
public unsafe FastSpringBoneBuffer(FastSpringBoneBufferBuilder b)
|
||||
{
|
||||
Profiler.BeginSample("FastSpringBone.ConstructBuffers");
|
||||
|
||||
_externalData = new NativeArray<BlittableExternalData>(1, Allocator.Persistent);
|
||||
ExternalData = externalData;
|
||||
|
||||
// Transformの列挙
|
||||
Profiler.BeginSample("FastSpringBone.ConstructBuffers.ConstructTransformBuffer");
|
||||
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();
|
||||
var transformIndexDictionary = transforms.Select((trs, index) => (trs, index))
|
||||
.ToDictionary(tuple => tuple.trs, tuple => tuple.index);
|
||||
Profiler.EndSample();
|
||||
|
||||
// 各種bufferの構築
|
||||
Profiler.BeginSample("FastSpringBone.ConstructBuffers.ConstructBuffers");
|
||||
var blittableColliders = new List<BlittableCollider>();
|
||||
var blittableJoints = new List<BlittableJoint>();
|
||||
var blittableSprings = new List<BlittableSpring>();
|
||||
var blittableLogics = new List<BlittableLogic>();
|
||||
|
||||
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 = simulateLastBone ? spring.joints.Length : spring.joints.Length - 1,
|
||||
},
|
||||
centerTransformIndex = spring.center ? transformIndexDictionary[spring.center] : -1,
|
||||
ExternalData = (BlittableExternalData*) _externalData.GetUnsafePtr()
|
||||
};
|
||||
blittableSprings.Add(blittableSpring);
|
||||
|
||||
blittableColliders.AddRange(spring.colliders.Select(collider =>
|
||||
{
|
||||
var blittable = collider.Collider;
|
||||
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;
|
||||
}));
|
||||
|
||||
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 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 = transformIndexDictionary[joint.Transform],
|
||||
parentTransformIndex = parent != null ? transformIndexDictionary[parent] : -1,
|
||||
currentTail = currentTail,
|
||||
prevTail = currentTail,
|
||||
localRotation = joint.DefaultLocalRotation,
|
||||
boneAxis = localChildPosition.normalized,
|
||||
length = localChildPosition.magnitude
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
// 各種bufferの初期化
|
||||
Profiler.BeginSample("FastSpringBone.ConstructBuffers.ConstructNativeArrays");
|
||||
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);
|
||||
Transforms = transforms.ToArray();
|
||||
Profiler.EndSample();
|
||||
|
||||
_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;
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
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 FastSpringBoneBufferBuilder(IEnumerable<FastSpringBoneSpring> springs, bool simulateLastBone = false)
|
||||
{
|
||||
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();
|
||||
var transformIndexDictionary = Transforms.Select((trs, index) => (trs, index))
|
||||
.ToDictionary(tuple => tuple.trs, tuple => tuple.index);
|
||||
|
||||
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 = simulateLastBone ? spring.joints.Length : spring.joints.Length - 1,
|
||||
},
|
||||
centerTransformIndex = spring.center ? transformIndexDictionary[spring.center] : -1,
|
||||
};
|
||||
BlittableSprings.Add(blittableSpring);
|
||||
|
||||
BlittableColliders.AddRange(spring.colliders.Select(collider =>
|
||||
{
|
||||
var blittable = collider.Collider;
|
||||
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;
|
||||
}));
|
||||
|
||||
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 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 = transformIndexDictionary[joint.Transform],
|
||||
parentTransformIndex = parent != null ? transformIndexDictionary[parent] : -1,
|
||||
currentTail = currentTail,
|
||||
prevTail = currentTail,
|
||||
localRotation = joint.DefaultLocalRotation,
|
||||
boneAxis = localChildPosition.normalized,
|
||||
length = localChildPosition.magnitude
|
||||
});
|
||||
}
|
||||
}
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
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];
|
||||
BlittableSprings[i] = new BlittableSpring
|
||||
{
|
||||
centerTransformIndex = b.centerTransformIndex,
|
||||
colliderSpan = b.colliderSpan,
|
||||
logicSpan = b.logicSpan,
|
||||
transformIndexOffset = b.transformIndexOffset,
|
||||
ExternalData = externalData,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82dbc85cfa7168546b209a51f6342d84
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user