This commit is contained in:
ousttrue
2024-06-05 15:54:03 +09:00
parent 31fac6cad6
commit a71aa9fd8f
6 changed files with 125 additions and 7 deletions

View File

@@ -27,6 +27,8 @@ namespace UniVRM10
public Vector3 Normal = Vector3.up;
public Vector3 TailOrNormal => ColliderType == VRM10SpringBoneColliderTypes.Plane ? Normal : Tail;
public static int SelectedGuid;
public bool IsSelected => GetInstanceID() == SelectedGuid;

View File

@@ -131,7 +131,7 @@ namespace UniVRM10
{
offset = collider.Offset,
radius = collider.Radius,
tail = collider.Tail,
tailOrNormal = collider.TailOrNormal,
colliderType = TranslateColliderType(collider.ColliderType)
}
}).ToArray(),

View File

@@ -9,11 +9,12 @@ namespace UniVRM10.FastSpringBones.Blittables
/// </summary>
[Serializable]
public struct BlittableCollider
{
{
public BlittableColliderType colliderType;
public Vector3 offset;
public float radius;
public Vector3 tail;
// capsule tail or plane normal
public Vector3 tailOrNormal;
public int transformIndex;
}
}

View File

@@ -4,5 +4,7 @@ namespace UniVRM10.FastSpringBones.Blittables
{
Sphere,
Capsule,
Plane,
SphereInside,
}
}

View File

@@ -22,7 +22,7 @@ namespace UniVRM10.FastSpringBones.System
[NativeDisableParallelForRestriction] public NativeArray<BlittableTransform> Transforms;
public float DeltaTime;
public unsafe void Execute(int index)
{
var spring = Springs[index];
@@ -79,16 +79,28 @@ namespace UniVRM10.FastSpringBones.System
var colliderScale = colliderTransform.localToWorldMatrix.lossyScale;
var maxColliderScale = Mathf.Max(Mathf.Max(Mathf.Abs(colliderScale.x), Mathf.Abs(colliderScale.y)), Mathf.Abs(colliderScale.z));
var worldPosition = colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.offset);
var worldTail = colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.tail);
var worldTail = colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.tailOrNormal);
switch (collider.colliderType)
{
case BlittableColliderType.Sphere:
ResolveSphereCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail);
ResolveSphereCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail);
break;
case BlittableColliderType.Capsule:
ResolveCapsuleCollision(worldTail, worldPosition, headTransform, joint, collider, maxColliderScale, logic, ref nextTail);
break;
case BlittableColliderType.Plane:
ResolvePlaneCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail);
break;
case BlittableColliderType.SphereInside:
ResolveSphereCollisionInside(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail);
break;
default:
throw new NotImplementedException();
}
}
@@ -203,5 +215,71 @@ namespace UniVRM10.FastSpringBones.System
nextTail = headTransform.position + (posFromCollider - headTransform.position).normalized * logic.length;
}
}
private static void ResolveSphereCollisionInside(
BlittableJoint joint,
BlittableCollider collider,
Vector3 worldPosition,
BlittableTransform headTransform,
float maxColliderScale,
BlittableLogic logic,
ref Vector3 nextTail)
{
var r = joint.radius + collider.radius * maxColliderScale;
if (Vector3.SqrMagnitude(nextTail - worldPosition) <= (r * r))
{
// ヒット。Colliderの半径方向に押し出す
var normal = (nextTail - worldPosition).normalized;
var posFromCollider = worldPosition + normal * r;
// 長さをboneLengthに強制
nextTail = headTransform.position + (posFromCollider - headTransform.position).normalized * logic.length;
}
// let transformedOffset = colliderOffset * colliderTransform;
// let transformedTail = colliderTail * colliderTransform;
// let offsetToTail = transformedTail - transformedOffset;
// let lengthSqCapsule = lengthSq(offsetToTail);
// let dot = dot(offsetToTail, delta);
// var delta = jointPosition - transformedOffset;
// if (dot < 0.0) {
// // ジョイントがカプセルの始点側にある場合
// // なにもしない
// } else if (dot > lengthSqCapsule) {
// // ジョイントがカプセルの終点側にある場合
// delta -= offsetToTail;
// } else {
// // ジョイントがカプセルの始点と終点の間にある場合
// delta -= offsetToTail * (dot / lengthSqCapsule);
// }
// // ジョイントとコライダーの距離。負の値は衝突していることを示す
// let distance = colliderRadius - jointRadius - length(delta);
// // ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す
// let direction = -normalize(delta);
}
private static void ResolvePlaneCollision(
BlittableJoint joint,
BlittableCollider collider,
Vector3 worldPosition,
BlittableTransform headTransform,
float maxColliderScale,
BlittableLogic logic,
ref Vector3 nextTail)
{
// let transformedOffset = colliderOffset * colliderTransform;
// let transformedNormal = normalize(colliderNormal * normalMatrixFrom(colliderTransform));
// let delta = jointPosition - transformedOffset;
// // ジョイントとコライダーの距離。負の値は衝突していることを示す
// let distance = dot(delta, transformedNormal) - jointRadius;
// // ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す
// let direction = transformedNormal;
}
}
}

View File

@@ -538,6 +538,41 @@ namespace UniVRM10
{
throw new Vrm10Exception("unknown shape");
}
// https://github.com/vrm-c/vrm-specification/tree/master/specification/VRMC_springBone_extended_collider-1.0
// VRMC_springBone_extended_collider
if (UniGLTF.Extensions.VRMC_springBone_extended_collider.GltfDeserializer.TryGet(c.Extensions as glTFExtension,
out UniGLTF.Extensions.VRMC_springBone_extended_collider.VRMC_springBone_extended_collider exCollider))
{
if (exCollider.Shape.Sphere is UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeSphere exSphere)
{
collider.ColliderType = VRM10SpringBoneColliderTypes.Sphere;
collider.Offset = Vector3InvertX(exSphere.Offset);
collider.Radius = exSphere.Radius.Value;
if (exSphere.Inside.HasValue && exSphere.Inside.Value)
{
collider.ColliderType = VRM10SpringBoneColliderTypes.SphereIside;
}
}
else if (exCollider.Shape.Capsule is UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapeCapsule exCapsule)
{
collider.ColliderType = VRM10SpringBoneColliderTypes.Capsule;
collider.Offset = Vector3InvertX(exCapsule.Offset);
collider.Tail = Vector3InvertX(exCapsule.Tail);
collider.Radius = exCapsule.Radius.Value;
}
else if (exCollider.Shape.Plane is UniGLTF.Extensions.VRMC_springBone_extended_collider.ExtendedColliderShapePlane exPlane)
{
collider.ColliderType = VRM10SpringBoneColliderTypes.Plane;
collider.Offset = Vector3InvertX(exPlane.Offset);
collider.Normal = Vector3InvertX(exPlane.Normal);
collider.Radius = 0.1f; // gizmo visualize. 10cm
}
else
{
throw new Vrm10Exception("VRMC_springBone_extended_collider: unknown shape");
}
}
}
}