Merge branch 'master' into customShaderImport

This commit is contained in:
ousttrue 2025-08-22 16:46:37 +09:00 committed by GitHub
commit f69ebf823e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
68 changed files with 1165 additions and 452 deletions

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b09ae318bccbfce4993fafb418e1e8c7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,91 @@
using UniGLTF.SpringBoneJobs.Blittables;
using Unity.Mathematics;
namespace UniGLTF.SpringBoneJobs
{
public static class Anglelimit
{
public static float3 Apply(
in BlittableJointImmutable logic, in BlittableJointMutable joint,
in quaternion parentRotation, in float3 head, in float3 nextTail)
{
switch (joint.anglelimitType)
{
case AnglelimitTypes.None:
// do nothing
return nextTail;
case AnglelimitTypes.Cone:
{
var angleSpaceToWorld = anglelimitSpaceToWorld(logic, joint, parentRotation);
var tailDir = math.mul(math.inverse(angleSpaceToWorld), math.normalize(nextTail - head));
tailDir = AnglelimitCone.Apply(tailDir, joint.anglelimit1);
return head + math.mul(angleSpaceToWorld, tailDir) * logic.length;
}
case AnglelimitTypes.Hinge:
{
var angleSpaceToWorld = anglelimitSpaceToWorld(logic, joint, parentRotation);
var tailDir = math.mul(math.inverse(angleSpaceToWorld), math.normalize(nextTail - head));
tailDir = AnglelimitHinge.Apply(tailDir, joint.anglelimit1);
return head + math.mul(angleSpaceToWorld, tailDir) * logic.length;
}
case AnglelimitTypes.Spherical:
{
var angleSpaceToWorld = anglelimitSpaceToWorld(logic, joint, parentRotation);
var tailDir = math.mul(math.inverse(angleSpaceToWorld), math.normalize(nextTail - head));
tailDir = AnglelimitSpherical.Apply(tailDir, joint.anglelimit1, joint.anglelimit2);
return head + math.mul(angleSpaceToWorld, tailDir) * logic.length;
}
default:
throw new System.ArgumentException($"unknown joint.anglelimitType: {joint.anglelimitType}");
}
}
/// <param name="nextTail">nextTail(position vector in world space)</param>
/// <returns>tailDir(directionay vector in angle space)</returns>
/// <exception cref="System.NotImplementedException"></exception>
public static quaternion anglelimitSpaceToWorld(in BlittableJointImmutable logic, in BlittableJointMutable joint,
in quaternion parentRotation)
{
// Y+方向からjointのheadからtailに向かうベクトルへの最小回転
var axisRotation = fromToQuaternion(new float3(0, 1, 0), logic.boneAxis);
// limitのローカル空間をワールド空間に写像する回転
return
math.mul(parentRotation,
math.mul(logic.localRotation,
math.mul(axisRotation,
joint.anglelimitOffset)))
;
}
// https://discussions.unity.com/t/unity-mathematics-equivalent-to-quaternion-fromtorotation/237459
public static quaternion fromToQuaternion(in float3 from, in float3 to)
{
var fromNorm = math.normalize(from);
var toNorm = math.normalize(to);
var dot = math.dot(fromNorm, toNorm);
// Handle the case where from and to are parallel but opposite
if (math.abs(dot + 1f) < 1e-6f) // dot is approximately -1
{
// Find a perpendicular axis
var perpAxis = math.abs(fromNorm.x) > math.abs(fromNorm.z)
? new float3(-fromNorm.y, fromNorm.x, 0f)
: new float3(0f, -fromNorm.z, fromNorm.y);
return quaternion.AxisAngle(math.normalize(perpAxis), math.PI);
}
// General case
return quaternion.AxisAngle(
angle: math.acos(math.clamp(dot, -1f, 1f)),
axis: math.normalize(math.cross(fromNorm, toNorm))
);
}
}
}

View File

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

View File

@ -0,0 +1,33 @@
using Unity.Mathematics;
namespace UniGLTF.SpringBoneJobs
{
public static class AnglelimitCone
{
/// <param name="src">AngleLimit空間の方向ベクトル</param>
/// <param name="angleLimit">radius</param>
/// <returns>AngleLimit空間の方向ベクトル</returns>
public static float3 Apply(in float3 src, float angleLimit)
{
// tailDirのy要素をjointに設定されたangleの余弦と比較する
var cosAngle = math.cos(angleLimit);
if (src.y >= cosAngle)
{
return src;
}
var tailDir = src;
{
// x・z要素を、tailDirの正弦とjointに設定されたangleの正弦の比を用いてスケールする
var ratio = math.sqrt((1.0f - cosAngle * cosAngle) / (1.0f - tailDir.y * tailDir.y));
tailDir.x *= ratio;
tailDir.z *= ratio;
// y要素を、jointに設定されたangleの余弦とする
tailDir.y = cosAngle;
}
return tailDir;
}
}
}

View File

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

View File

@ -0,0 +1,32 @@
using Unity.Mathematics;
namespace UniGLTF.SpringBoneJobs
{
public static class AnglelimitHinge
{
/// <param name="src">AngleLimit空間の方向ベクトル</param>
/// <param name="angleLimit">radius</param>
/// <returns>AngleLimit空間の方向ベクトル</returns>
public static float3 Apply(in float3 src, float limitAngle)
{
// x要素を0にし、正規化する
float3 tailDir = src;
tailDir.x = 0.0f;
tailDir = math.normalize(tailDir);
// tailDirのy要素をjointに設定されたangleの余弦と比較する
var cosAngle = math.cos(limitAngle);
if (tailDir.y < cosAngle)
{
// z要素を、tailDirの正弦とjointに設定されたangleの正弦の比を用いてスケールする
var ratio = math.sqrt((1.0f - cosAngle * cosAngle) / (1.0f - tailDir.y * tailDir.y));
tailDir.z *= ratio;
// y要素を、jointに設定されたangleの余弦とする
tailDir.y = cosAngle;
}
return tailDir;
}
}
}

View File

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

View File

@ -0,0 +1,37 @@
using Unity.Mathematics;
namespace UniGLTF.SpringBoneJobs
{
public static class AnglelimitSpherical
{
/// <param name="tailDir">AngleLimit空間の方向ベクトル</param>
/// <param name="limitAnglePhi">radius</param>
/// <param name="limitAngleTheta">radius</param>
/// <returns>AngleLimit空間の方向ベクトル</returns>
public static float3 Apply(in float3 tailDir, float limitAnglePhi, float limitAngleTheta)
{
// tailDirのphi・thetaを計算する
var phi = math.atan2(tailDir.z, tailDir.y);
var theta = math.asin(tailDir.x);
// phi・thetaをjointに設定されたphi・thetaを用いて制限する
// var isLimited = false;
if (math.abs(phi) > limitAnglePhi)
{
// isLimited = true;
phi = limitAnglePhi * math.sign(phi);
}
// thetaをjointに設定されたthetaを用いて制限する
if (math.abs(theta) > limitAngleTheta)
{
// isLimited = true;
theta = limitAngleTheta * math.sign(theta);
}
// tailDirをphi・thetaを用いて再計算する
var cos_theta = math.cos(theta);
return new float3(math.sin(theta), cos_theta * math.cos(phi), cos_theta * math.sin(phi));
}
}
}

View File

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

View File

@ -0,0 +1,11 @@
namespace UniGLTF.SpringBoneJobs
{
public enum AnglelimitTypes
{
None,
Cone,
Hinge,
Spherical,
}
}

View File

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

View File

@ -1,4 +1,5 @@
using System;
using Unity.Mathematics;
using UnityEngine;
namespace UniGLTF.SpringBoneJobs.Blittables
@ -7,15 +8,35 @@ namespace UniGLTF.SpringBoneJobs.Blittables
/// Blittableなコライダ
/// </summary>
[Serializable]
public struct BlittableCollider
public readonly struct BlittableCollider
{
public BlittableColliderType colliderType;
public Vector3 offset;
public float radius;
// capsule tail or plane normal
public Vector3 tailOrNormal;
public int transformIndex;
private readonly float3x3 _data;
public BlittableColliderType colliderType => (BlittableColliderType)(int)_data.c2.y;
public float3 offset => _data.c0;
public float radius => _data.c2.x;
// capsule tail or plane normal
public float3 tailOrNormal => _data.c1;
public int transformIndex => (int)_data.c2.z;
public BlittableCollider(
float3 offset = default,
float radius = 0,
float3 tailOrNormal = default,
BlittableColliderType colliderType = default,
int colliderTransformIndex = 0)
{
var c0 = offset;
var c1 = tailOrNormal;
var c2 = new float3(radius,(int)colliderType, colliderTransformIndex);
_data = new float3x3(c0, c1, c2);
}
public BlittableCollider SetTransformIndex(int index)
{
return new BlittableCollider(offset, radius, tailOrNormal, colliderType, index);
}
public void DrawGizmo(BlittableTransform t)
{
Gizmos.matrix = t.localToWorldMatrix;

View File

@ -1,4 +1,5 @@
using System;
using Unity.Mathematics;
using UnityEngine;
namespace UniGLTF.SpringBoneJobs.Blittables
@ -9,15 +10,31 @@ namespace UniGLTF.SpringBoneJobs.Blittables
/// 変わりにくいスコープ。
/// </summary>
[Serializable]
public struct BlittableJointImmutable
public readonly struct BlittableJointImmutable
{
public int parentTransformIndex;
public int headTransformIndex;
public int tailTransformIndex;
public float length;
public Quaternion localRotation;
public Vector3 boneAxis;
private readonly float4x3 _data;
public int parentTransformIndex => (int)_data.c2.x;
public int headTransformIndex => (int)_data.c2.y;
public int tailTransformIndex => (int)_data.c2.z;
public float length => _data.c2.w;
public quaternion localRotation => _data.c0;
public float3 boneAxis => _data.c1.xyz;
public BlittableJointImmutable(
int parentTransformIndex = 0,
int headTransformIndex = 0,
int tailTransformIndex = 0,
float length = 0,
quaternion localRotation = default,
float3 boneAxis = default)
{
var c0 = localRotation.value;
var c1 = new float4(boneAxis, 0);
var c2 = new float4(parentTransformIndex, headTransformIndex, tailTransformIndex, length);
_data = new float4x3(c0, c1, c2);
}
public void DrawGizmo(BlittableTransform t, BlittableJointMutable m)
{
Gizmos.matrix = t.localToWorldMatrix;

View File

@ -1,5 +1,5 @@
using System;
using UnityEngine;
using Unity.Mathematics;
namespace UniGLTF.SpringBoneJobs.Blittables
{
@ -10,12 +10,50 @@ namespace UniGLTF.SpringBoneJobs.Blittables
/// JointReconfigure を呼ばなければ以前と同じで不変となる。
/// </summary>
[Serializable]
public struct BlittableJointMutable
public readonly struct BlittableJointMutable
{
public float stiffnessForce;
public float gravityPower;
public Vector3 gravityDir;
public float dragForce;
public float radius;
/// <summary>
/// |x |y |z |w |
/// |--------|--------|--------|--------|
/// |stiff |g-power |drag |radius |
/// |g-dir.x |g-dir.y |g-dir.z | |
/// |al.type |limit1 |limit2 |
/// |offset.x|offset.y|offset.z|offset.w|
///
/// g-power = gravityPower
/// g-dir = gravityDir
/// al = anglelimit
/// offset = anglelimitOffset
/// </summary>
private readonly float4x4 _data;
public float stiffnessForce => _data.c0.x;
public float gravityPower => _data.c0.y;
public float3 gravityDir => _data.c1.xyz;
public float dragForce => _data.c0.z;
public float radius => _data.c0.w;
public AnglelimitTypes anglelimitType => (AnglelimitTypes)_data.c2.x;
public float anglelimit1 => _data.c2.y;
public float anglelimit2 => _data.c2.z;
public quaternion anglelimitOffset => _data.c3.xyzw;
public BlittableJointMutable(float stiffnessForce = 0,
float gravityPower = 0,
float3 gravityDir = default,
float dragForce = 0,
float radius = 0,
// v0.129.4 anglelimit
float angleLimitType = 0,
float angleLimit1 = 0,
float angleLimit2 = 0,
quaternion angleLimitOffset = default)
{
var c0 = new float4(stiffnessForce, gravityPower, dragForce, radius);
var c1 = new float4(gravityDir, 0);
var c2 = new float4(angleLimitType, angleLimit1, angleLimit2, 0);
var c3 = angleLimitOffset.value;
_data = new float4x4(c0, c1, c2, c3);
}
}
}

View File

@ -1,23 +1,33 @@
using UnityEngine;
using Unity.Mathematics;
namespace UniGLTF.SpringBoneJobs.Blittables
{
public struct BlittableModelLevel
public readonly struct BlittableModelLevel
{
private readonly float4 _data;
/// <summary>
/// World 座標系の追加の力。風など。
/// </summary>
public Vector3 ExternalForce;
public float3 ExternalForce => _data.xyz;
/// <summary>
/// 処理結果の Transform への書き戻しを停止する。
/// </summary>
public bool StopSpringBoneWriteback;
public bool StopSpringBoneWriteback => ((int)_data.w & 1) != 0;
/// <summary>
/// スケール値に連動して SpringBone のパラメータを自動調整する。
/// (見た目の角速度が同じになるようにする)
/// </summary>
public bool SupportsScalingAtRuntime;
public bool SupportsScalingAtRuntime => ((int)_data.w & 2) != 0;
public BlittableModelLevel(float3 externalForce = default,
bool stopSpringBoneWriteback = false,
bool supportsScalingAtRuntime = false)
{
var w = (stopSpringBoneWriteback ? 1 : 0) | ((supportsScalingAtRuntime ? 1 : 0) << 1);
_data = new float4(externalForce, w);
}
}
}

View File

@ -3,11 +3,20 @@ using System;
namespace UniGLTF.SpringBoneJobs.Blittables
{
[Serializable]
public struct BlittableSpan
public readonly struct BlittableSpan
{
public int startIndex;
public int count;
private readonly int _startIndex;
private readonly int _count;
public int startIndex => _startIndex;
public int count => _count;
public int EndIndex => startIndex + count;
public BlittableSpan(int startIndex, int count)
{
_startIndex = startIndex;
_count = count;
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using Unity.Mathematics;
namespace UniGLTF.SpringBoneJobs.Blittables
{
@ -7,12 +8,21 @@ namespace UniGLTF.SpringBoneJobs.Blittables
/// FastSpringBoneではこれを起点として並列化し、処理を行う
/// </summary>
[Serializable]
public struct BlittableSpring
public readonly struct BlittableSpring
{
public BlittableSpan colliderSpan;
public BlittableSpan logicSpan;
public int centerTransformIndex;
public int transformIndexOffset;
public int modelIndex;
private readonly int4x2 _data;
public BlittableSpan colliderSpan => new(_data.c0.x, _data.c0.y);
public BlittableSpan logicSpan => new(_data.c0.z, _data.c0.w);
public int centerTransformIndex => _data.c1.x;
public int transformIndexOffset => _data.c1.y;
public int modelIndex => _data.c1.z;
public BlittableSpring(BlittableSpan colliderSpan = default, BlittableSpan logicSpan = default, int centerTransformIndex = 0, int transformIndexOffset = 0, int modelIndex = 0)
{
var c0 = new int4(colliderSpan.startIndex, colliderSpan.count, logicSpan.startIndex, logicSpan.count);
var c1 = new int4(centerTransformIndex, transformIndexOffset, modelIndex, 0);
_data = new int4x2(c0, c1);
}
}
}

View File

@ -1,5 +1,7 @@
using System;
using UnityEngine;
using System.Runtime.CompilerServices;
using Unity.Mathematics;
using UnityEngine.Jobs;
namespace UniGLTF.SpringBoneJobs.Blittables
{
@ -7,14 +9,147 @@ namespace UniGLTF.SpringBoneJobs.Blittables
/// Transformの必要な機能だけを絞り、Blittableに対応させたクラス
/// </summary>
[Serializable]
public struct BlittableTransform
public readonly struct BlittableTransform
{
public Vector3 position;
public Quaternion rotation;
public Vector3 localPosition;
public Quaternion localRotation;
public Vector3 localScale;
public Matrix4x4 localToWorldMatrix;
public Matrix4x4 worldToLocalMatrix;
private readonly float4x3 _localData;
private readonly float4x4 _globalData;
public float3 position => GetPosition();
public quaternion rotation => GetRotation();
public float3 lossyScale => GetLossyScale();
public float3 localPosition => _localData.c0.xyz;
public quaternion localRotation => _localData.c1;
public float3 localScale => _localData.c2.xyz;
public float4x4 localToWorldMatrix => GetLocalToWorldMatrix();
public float4x4 worldToLocalMatrix => math.inverse(localToWorldMatrix);
public static BlittableTransform FromTransformAccess(TransformAccess transform)
{
return new BlittableTransform(
transform.rotation,
transform.localPosition,
transform.localRotation,
transform.localScale,
transform.localToWorldMatrix);
}
private BlittableTransform(
quaternion rotation,
float3 localPosition,
quaternion localRotation,
float3 localScale,
float4x4 localToWorldMatrix)
{
var c10 = new float4(localPosition, 0);
var c11 = localRotation;
var c12 = new float4(localScale, 0);
_localData = new float4x3(c10, c11.value, c12);
var c20 = new float4(localToWorldMatrix.c0.xyz, rotation.value.x);
var c21 = new float4(localToWorldMatrix.c1.xyz, rotation.value.y);
var c22 = new float4(localToWorldMatrix.c2.xyz, rotation.value.z);
var c23 = new float4(localToWorldMatrix.c3.xyz, rotation.value.w);
_globalData = new float4x4(c20, c21, c22, c23);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private float4x4 GetLocalToWorldMatrix()
{
var c0 = new float4(_globalData.c0.xyz, 0);
var c1 = new float4(_globalData.c1.xyz, 0);
var c2 = new float4(_globalData.c2.xyz, 0);
var c3 = new float4(_globalData.c3.xyz, 1);
return new float4x4(c0, c1, c2, c3);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private float3 GetPosition()
{
return localToWorldMatrix.c3.xyz;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private quaternion GetRotation()
{
return new quaternion(_globalData.c0.w, _globalData.c1.w, _globalData.c2.w, _globalData.c3.w);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private float3 GetLossyScale()
{
float4x4 tr = float4x4.TRS(position, rotation, new float3(1.0f));
float4x4 m = math.mul(math.inverse(tr), localToWorldMatrix);
return new float3(m.c0.x, m.c1.y, m.c2.z);
}
/// <summary>
/// 親Transformが移動や回転を行った際に、ローカル座標系の値をもとに新しい絶対座標系でのTransformを計算します。
/// </summary>
/// <param name="parent"></param>
/// <returns></returns>
public BlittableTransform UpdateParentMatrix(BlittableTransform parent)
{
quaternion newRotation = math.mul(parent.rotation, localRotation);
float4x4 newLocalToWorldMatrix = math.mul(parent.localToWorldMatrix, float4x4.TRS(localPosition, localRotation, localScale));
return new BlittableTransform(newRotation, localPosition, localRotation, localScale, newLocalToWorldMatrix);
}
/// <summary>
/// グローバル座標系での位置を更新し、それに伴って連動する他の値も更新します。
/// </summary>
/// <param name="newValue"></param>
/// <param name="parent"></param>
/// <returns></returns>
public BlittableTransform UpdatePosition(float3 newValue, BlittableTransform? parent = null)
{
quaternion newRotation;
float3 newLocalPosition;
quaternion newLocalRotation;
float4x4 newLocalToWorldMatrix;
if(parent.HasValue)
{
newLocalPosition = math.transform(parent.Value.worldToLocalMatrix, newValue);
newLocalRotation = math.mul(math.inverse(parent.Value.rotation), rotation);
newRotation = math.mul(parent.Value.rotation, newLocalRotation);
newLocalToWorldMatrix = math.mul(parent.Value.localToWorldMatrix, float4x4.TRS(newLocalPosition, newLocalRotation, localScale));
}
else
{
newLocalPosition = newValue;
newLocalRotation = rotation;
newRotation = rotation;
newLocalToWorldMatrix = float4x4.TRS(newValue, newRotation, localScale);
}
return new BlittableTransform(newRotation, newLocalPosition, newLocalRotation, localScale, newLocalToWorldMatrix);
}
/// <summary>
/// グローバル座標系での回転を更新し、それに伴って連動する他の値も更新します。
/// </summary>
/// <param name="newValue"></param>
/// <param name="parent"></param>
/// <returns></returns>
public BlittableTransform UpdateRotation(quaternion newValue, BlittableTransform? parent = null)
{
quaternion newRotation = newValue;
quaternion newLocalRotation;
float4x4 newLocalToWorldMatrix;
if(parent.HasValue)
{
newLocalRotation = math.normalize(math.mul(math.inverse(parent.Value.rotation), newRotation));
newLocalToWorldMatrix = math.mul(parent.Value.localToWorldMatrix, float4x4.TRS(localPosition, newLocalRotation, localScale));
}
else
{
newLocalRotation = newValue;
newLocalToWorldMatrix = float4x4.TRS(position, newRotation, localScale);
}
return new BlittableTransform(newRotation, localPosition, newLocalRotation, localScale, newLocalToWorldMatrix);
}
}
}
}

View File

@ -5,10 +5,12 @@ using Unity.Burst;
using System;
using System.Collections.Generic;
using System.Linq;
using UniGLTF.Runtime.Utils;
using UniGLTF.SpringBoneJobs.Blittables;
using UniGLTF.SpringBoneJobs.InputPorts;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Jobs;
using UnityEngine.Profiling;
@ -23,9 +25,9 @@ namespace UniGLTF.SpringBoneJobs
// Joint Level
private NativeArray<BlittableJointImmutable> _logics;
private NativeArray<BlittableJointMutable> _joints;
private NativeArray<Vector3> _prevTails;
private NativeArray<Vector3> _currentTails;
private NativeArray<Vector3> _nextTails;
private NativeArray<float3> _prevTails;
private NativeArray<float3> _currentTails;
private NativeArray<float3> _nextTails;
// Spring Level
private NativeArray<BlittableSpring> _springs;
// Moodel Level
@ -39,9 +41,9 @@ namespace UniGLTF.SpringBoneJobs
// accessor: Joint Level
public NativeArray<BlittableJointImmutable> Logics => _logics;
public NativeArray<BlittableJointMutable> Joints => _joints;
public NativeArray<Vector3> PrevTails => _prevTails;
public NativeArray<Vector3> CurrentTails => _currentTails;
public NativeArray<Vector3> NextTails => _nextTails;
public NativeArray<float3> PrevTails => _prevTails;
public NativeArray<float3> CurrentTails => _currentTails;
public NativeArray<float3> NextTails => _nextTails;
// accessor: Spring Level
public NativeArray<BlittableSpring> Springs => _springs;
// accessor: Model LEvel
@ -64,9 +66,9 @@ namespace UniGLTF.SpringBoneJobs
// joint level
_logics = new NativeArray<BlittableJointImmutable>(logicsCount, Allocator.Persistent);
_joints = new NativeArray<BlittableJointMutable>(logicsCount, Allocator.Persistent);
_prevTails = new NativeArray<Vector3>(logicsCount, Allocator.Persistent);
_currentTails = new NativeArray<Vector3>(logicsCount, Allocator.Persistent);
_nextTails = new NativeArray<Vector3>(logicsCount, Allocator.Persistent);
_prevTails = new NativeArray<float3>(logicsCount, Allocator.Persistent);
_currentTails = new NativeArray<float3>(logicsCount, Allocator.Persistent);
_nextTails = new NativeArray<float3>(logicsCount, Allocator.Persistent);
// spring level
_springs = new NativeArray<BlittableSpring>(springsCount, Allocator.Persistent);
// model level
@ -248,11 +250,12 @@ namespace UniGLTF.SpringBoneJobs
public void Execute(int index)
{
var spring = SrcSprings[index];
spring.modelIndex = ModelIndex;
spring.colliderSpan.startIndex += CollidersOffset;
spring.logicSpan.startIndex += LogicsOffset;
spring.transformIndexOffset = TransformOffset;
DestSprings[index] = spring;
DestSprings[index] = new BlittableSpring(
modelIndex: ModelIndex,
colliderSpan: new BlittableSpan(spring.colliderSpan.startIndex + CollidersOffset, spring.colliderSpan.count),
logicSpan: new BlittableSpan(spring.logicSpan.startIndex + LogicsOffset, spring.logicSpan.count),
transformIndexOffset: TransformOffset,
centerTransformIndex: spring.centerTransformIndex);
}
}
@ -296,9 +299,9 @@ namespace UniGLTF.SpringBoneJobs
[ReadOnly] public NativeArray<BlittableJointImmutable> Logics;
[ReadOnly] public NativeArray<BlittableTransform> Transforms;
[NativeDisableParallelForRestriction] public NativeSlice<Vector3> CurrentTails;
[NativeDisableParallelForRestriction] public NativeSlice<Vector3> PrevTails;
[NativeDisableParallelForRestriction] public NativeSlice<Vector3> NextTails;
[NativeDisableParallelForRestriction] public NativeSlice<float3> CurrentTails;
[NativeDisableParallelForRestriction] public NativeSlice<float3> PrevTails;
[NativeDisableParallelForRestriction] public NativeSlice<float3> NextTails;
public void Execute(int springIndex)
{
@ -323,7 +326,7 @@ namespace UniGLTF.SpringBoneJobs
}
var tail = Transforms[tailIndex];
var tailPos = center.HasValue ? center.Value.worldToLocalMatrix.MultiplyPoint3x4(tail.position) : tail.position;
var tailPos = center.HasValue ? MathHelper.MultiplyPoint3x4(center.Value.worldToLocalMatrix, tail.position) : tail.position;
CurrentTails[jointIndex] = tailPos;
PrevTails[jointIndex] = tailPos;
NextTails[jointIndex] = tailPos;

View File

@ -18,9 +18,13 @@ namespace UniGLTF.SpringBoneJobs
_bufferCombiner.Dispose();
}
public JobHandle Schedule(float deltaTime)
public JobHandle Schedule(float deltaTime, JobHandle? dependency = null)
{
var handle = _bufferCombiner.ReconstructIfDirty(default);
if(dependency.HasValue)
{
handle = JobHandle.CombineDependencies(handle, dependency.Value);
}
if (!_bufferCombiner.HasBuffer)
{
return handle;

View File

@ -2,9 +2,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Profiling;
using UniGLTF.SpringBoneJobs.Blittables;
using Unity.Mathematics;
using UnityEngine;
namespace UniGLTF.SpringBoneJobs.InputPorts
{
@ -22,8 +23,8 @@ namespace UniGLTF.SpringBoneJobs.InputPorts
public NativeArray<BlittableJointMutable> Joints { get; }
public NativeArray<BlittableCollider> Colliders { get; }
public NativeArray<BlittableJointImmutable> Logics { get; }
private NativeArray<Vector3> _currentTailsBackup;
private NativeArray<Vector3> _nextTailsBackup;
private NativeArray<float3> _currentTailsBackup;
private NativeArray<float3> _nextTailsBackup;
public Transform[] Transforms { get; }
/// <summary>
@ -67,27 +68,17 @@ namespace UniGLTF.SpringBoneJobs.InputPorts
List<BlittableJointImmutable> 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),
};
var blittableSpring = new BlittableSpring(
centerTransformIndex: Array.IndexOf(Transforms, spring.center),
colliderSpan: new BlittableSpan(blittableColliders.Count, spring.colliders.Length),
logicSpan: new BlittableSpan(blittableJoints.Count, spring.joints.Length - 1));
blittableSprings.Add(blittableSpring);
blittableColliders.AddRange(spring.colliders.Select(collider =>
{
var blittable = collider.Collider;
blittable.transformIndex = Array.IndexOf(Transforms, collider.Transform);
return blittable;
var transformIndex = Array.IndexOf(Transforms, collider.Transform);
return blittable.SetTransformIndex(transformIndex);
}));
blittableJoints.AddRange(spring.joints
.Take(spring.joints.Length - 1).Select(joint =>
@ -123,25 +114,23 @@ namespace UniGLTF.SpringBoneJobs.InputPorts
var localPosition = tailJoint.Transform.localPosition;
var scale = tailJoint.Transform.lossyScale;
var localChildPosition = new Vector3(
var localChildPosition = new float3(
localPosition.x * scale.x,
localPosition.y * scale.y,
localPosition.z * scale.z
);
yield return new BlittableJointImmutable
{
headTransformIndex = Array.IndexOf<Transform>(Transforms, joint.Transform),
parentTransformIndex = Array.IndexOf<Transform>(Transforms, joint.Transform.parent),
tailTransformIndex = Array.IndexOf<Transform>(Transforms, tailJoint.Transform),
localRotation = joint.DefaultLocalRotation,
boneAxis = localChildPosition.normalized,
length = localChildPosition.magnitude
};
yield return new BlittableJointImmutable(
headTransformIndex: Array.IndexOf<Transform>(Transforms, joint.Transform),
parentTransformIndex: Array.IndexOf<Transform>(Transforms, joint.Transform.parent),
tailTransformIndex: Array.IndexOf<Transform>(Transforms, tailJoint.Transform),
localRotation: joint.DefaultLocalRotation,
boneAxis: math.normalize(localChildPosition),
length: math.length(localChildPosition));
}
}
public void BackupCurrentTails(NativeArray<Vector3> currentTails, NativeArray<Vector3> nextTails, int offset)
public void BackupCurrentTails(NativeArray<float3> currentTails, NativeArray<float3> nextTails, int offset)
{
if (!Logics.IsCreated || Logics.Length == 0)
{
@ -155,16 +144,16 @@ namespace UniGLTF.SpringBoneJobs.InputPorts
{
_nextTailsBackup = new(Logics.Length, Allocator.Persistent);
}
NativeArray<Vector3>.Copy(currentTails, offset, _currentTailsBackup, 0, Logics.Length);
NativeArray<Vector3>.Copy(nextTails, offset, _nextTailsBackup, 0, Logics.Length);
NativeArray<float3>.Copy(currentTails, offset, _currentTailsBackup, 0, Logics.Length);
NativeArray<float3>.Copy(nextTails, offset, _nextTailsBackup, 0, Logics.Length);
}
public void RestoreCurrentTails(NativeArray<Vector3> currentTails, NativeArray<Vector3> nextTails, int offset)
public void RestoreCurrentTails(NativeArray<float3> currentTails, NativeArray<float3> nextTails, int offset)
{
if (_currentTailsBackup.IsCreated)
{
NativeArray<Vector3>.Copy(_currentTailsBackup, 0, currentTails, offset, Logics.Length);
NativeArray<Vector3>.Copy(_nextTailsBackup, 0, nextTails, offset, Logics.Length);
NativeArray<float3>.Copy(_currentTailsBackup, 0, currentTails, offset, Logics.Length);
NativeArray<float3>.Copy(_nextTailsBackup, 0, nextTails, offset, Logics.Length);
}
else
{
@ -173,7 +162,7 @@ namespace UniGLTF.SpringBoneJobs.InputPorts
{
// mark velocity zero
#if UNITY_2022_2_OR_NEWER
currentTails.GetSubArray(offset, Logics.Length).AsSpan().Fill(new Vector3(float.NaN, float.NaN, float.NaN));
currentTails.GetSubArray(offset, Logics.Length).AsSpan().Fill(new float3(float.NaN, float.NaN, float.NaN));
#else
var subArray = currentTails.GetSubArray(offset, Logics.Length);
var value = new Vector3(float.NaN, float.NaN, float.NaN);

View File

@ -17,16 +17,7 @@ namespace UniGLTF.SpringBoneJobs
public void Execute(int index, TransformAccess transform)
{
Transforms[index] = new BlittableTransform
{
position = transform.position,
rotation = transform.rotation,
localPosition = transform.localPosition,
localRotation = transform.localRotation,
localScale = transform.localScale,
localToWorldMatrix = transform.localToWorldMatrix,
worldToLocalMatrix = transform.worldToLocalMatrix
};
Transforms[index] = BlittableTransform.FromTransformAccess(transform);
}
}
}

View File

@ -0,0 +1,206 @@
using UniGLTF.Runtime.Utils;
using UniGLTF.SpringBoneJobs.Blittables;
using Unity.Mathematics;
namespace UniGLTF.SpringBoneJobs
{
public static class SpringBoneCollision
{
public static bool TryCollide(
in BlittableJointImmutable logic, in BlittableJointMutable joint, in BlittableTransform headTransform,
in BlittableCollider collider, in BlittableTransform colliderTransform, float maxColliderScale,
in float3 colliderWorldTail, in float3 colliderWorldPosition,
in float3 nextTail, out float3 newNextTail)
{
switch (collider.colliderType)
{
case BlittableColliderType.Sphere:
return TryResolveSphereCollision(joint, collider, colliderWorldPosition, headTransform, maxColliderScale, logic, nextTail, out newNextTail);
case BlittableColliderType.Capsule:
return TryResolveCapsuleCollision(colliderWorldTail, colliderWorldPosition, headTransform, joint, collider, maxColliderScale, logic, nextTail, out newNextTail);
case BlittableColliderType.Plane:
return TryResolvePlaneCollision(joint, collider, colliderTransform, nextTail, out newNextTail);
case BlittableColliderType.SphereInside:
return TryResolveSphereCollisionInside(joint, collider, colliderTransform, nextTail, out newNextTail);
case BlittableColliderType.CapsuleInside:
return TryResolveCapsuleCollisionInside(joint, collider, colliderTransform, nextTail, out newNextTail);
default:
throw new System.NotImplementedException();
}
}
private static bool TryResolveSphereCollision(
in BlittableJointMutable joint,
in BlittableCollider collider,
in float3 worldPosition,
in BlittableTransform headTransform,
in float maxColliderScale,
in BlittableJointImmutable logic,
in float3 nextTail, out float3 newNextTail)
{
var r = joint.radius + collider.radius * maxColliderScale;
if (math.lengthsq(nextTail - worldPosition) <= (r * r))
{
// ヒット。Colliderの半径方向に押し出す
var normal = math.normalize(nextTail - worldPosition);
var posFromCollider = worldPosition + normal * r;
// 長さをboneLengthに強制
newNextTail = headTransform.position + math.normalize(posFromCollider - headTransform.position) * logic.length;
return true;
}
else
{
newNextTail = default;
return false;
}
}
private static bool TryResolveCapsuleCollision(
float3 worldTail,
float3 worldPosition,
BlittableTransform headTransform,
BlittableJointMutable joint,
BlittableCollider collider,
float maxColliderScale,
BlittableJointImmutable logic,
in float3 nextTail, out float3 newNextTail)
{
var direction = worldTail - worldPosition;
if (math.lengthsq(direction) == 0)
{
// head側半球の球判定
return TryResolveSphereCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, nextTail, out newNextTail);
}
var P = math.normalize(direction);
var Q = headTransform.position - worldPosition;
var dot = math.dot(P, Q);
if (dot <= 0)
{
// head側半球の球判定
return TryResolveSphereCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, nextTail, out newNextTail);
}
if (dot >= math.length(direction))
{
// tail側半球の球判定
return TryResolveSphereCollision(joint, collider, worldTail, headTransform, maxColliderScale, logic, nextTail, out newNextTail);
}
// head-tail上の m_transform.position との最近点
var p = worldPosition + P * dot;
return TryResolveSphereCollision(joint, collider, p, headTransform, maxColliderScale, logic, nextTail, out newNextTail);
}
/// <summary>
/// Collision with SpringJoint and PlaneCollider.
/// If collide update nextTail.
/// </summary>
/// <param name="joint">joint</param>
/// <param name="collider">collider</param>
/// <param name="colliderTransform">colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.offset);</param>
/// <param name="nextTail">result of verlet integration</param>
private static bool TryResolvePlaneCollision(
in BlittableJointMutable joint,
in BlittableCollider collider,
in BlittableTransform colliderTransform,
in float3 nextTail, out float3 newNextTail)
{
var transformedOffset = MathHelper.MultiplyPoint(colliderTransform.localToWorldMatrix, collider.offset);
var transformedNormal = math.normalize(MathHelper.MultiplyVector(colliderTransform.localToWorldMatrix, collider.tailOrNormal));
var delta = nextTail - transformedOffset;
// ジョイントとコライダーの距離。負の値は衝突していることを示す
var distance = math.dot(delta, transformedNormal) - joint.radius;
if (distance < 0)
{
// ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す
var direction = transformedNormal;
newNextTail = nextTail - direction * distance;
return true;
}
else
{
newNextTail = default;
return false;
}
}
private static bool TryResolveSphereCollisionInside(
in BlittableJointMutable joint,
in BlittableCollider collider,
in BlittableTransform colliderTransform,
in float3 nextTail, out float3 newNextTail)
{
var transformedOffset = MathHelper.MultiplyPoint(colliderTransform.localToWorldMatrix, collider.offset);
var delta = nextTail - transformedOffset;
// ジョイントとコライダーの距離。負の値は衝突していることを示す
var distance = collider.radius - joint.radius - math.length(delta);
// ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す
if (distance < 0)
{
var direction = -1 * math.normalize(delta);
newNextTail = nextTail - direction * distance;
return true;
}
else
{
newNextTail = default;
return false;
}
}
private static bool TryResolveCapsuleCollisionInside(
in BlittableJointMutable joint,
in BlittableCollider collider,
in BlittableTransform colliderTransform,
in float3 nextTail, out float3 newNextTail)
{
var transformedOffset = MathHelper.MultiplyPoint(colliderTransform.localToWorldMatrix, collider.offset);
var transformedTail = MathHelper.MultiplyPoint(colliderTransform.localToWorldMatrix, collider.tailOrNormal);
var offsetToTail = transformedTail - transformedOffset;
var lengthSqCapsule = math.lengthsq(offsetToTail);
var delta = nextTail - transformedOffset;
var dot = math.dot(offsetToTail, delta);
if (dot < 0.0)
{
// ジョイントがカプセルの始点側にある場合
// なにもしない
}
else if (dot > lengthSqCapsule)
{
// ジョイントがカプセルの終点側にある場合
delta -= offsetToTail;
}
else
{
// ジョイントがカプセルの始点と終点の間にある場合
delta -= offsetToTail * (dot / lengthSqCapsule);
}
// ジョイントとコライダーの距離。負の値は衝突していることを示す
var distance = collider.radius - joint.radius - math.length(delta);
// ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す
if (distance < 0)
{
var direction = -1 * math.normalize(delta);
newNextTail = nextTail - direction * distance;
return true;
}
else
{
newNextTail = default;
return false;
}
}
}
}

View File

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

View File

@ -2,7 +2,10 @@
"name": "SpringBoneJobs",
"rootNamespace": "",
"references": [
"GUID:8d76e605759c3f64a957d63ef96ada7c"
"GUID:8d76e605759c3f64a957d63ef96ada7c",
"GUID:1cd941934d098654fa21a13f28346412",
"GUID:2665a8d13d1b3f18800f46e256720795",
"GUID:d8b63aba1907145bea998dd612889d6b"
],
"includePlatforms": [],
"excludePlatforms": [],
@ -11,6 +14,12 @@
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"versionDefines": [
{
"name": "com.unity.burst",
"expression": "0.01",
"define": "ENABLE_SPRINGBONE_BURST"
}
],
"noEngineReferences": false
}

View File

@ -1,8 +1,9 @@
using System;
using UniGLTF.Runtime.Utils;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UniGLTF.SpringBoneJobs.Blittables;
using Unity.Mathematics;
#if ENABLE_SPRINGBONE_BURST
using Unity.Burst;
#endif
@ -26,10 +27,10 @@ namespace UniGLTF.SpringBoneJobs
// Joints, Logics, PrevTail, CurrentTail, NextTail は同じ index
[ReadOnly] public NativeArray<BlittableJointMutable> Joints;
[ReadOnly] public NativeArray<BlittableJointImmutable> Logics;
[ReadOnly] public NativeArray<Vector3> PrevTail;
[ReadOnly] public NativeArray<Vector3> CurrentTail;
[ReadOnly] public NativeArray<float3> PrevTail;
[ReadOnly] public NativeArray<float3> CurrentTail;
// 処理後の tail 位置(ランダムアクセス)
[NativeDisableParallelForRestriction] public NativeArray<Vector3> NextTail;
[NativeDisableParallelForRestriction] public NativeArray<float3> NextTail;
// Spring Level
[ReadOnly] public NativeArray<BlittableSpring> Springs;
// Model Level
@ -67,105 +68,65 @@ namespace UniGLTF.SpringBoneJobs
// 親があったら、親に依存するTransformを再計算
if (parentTransform.HasValue)
{
headTransform.position =
parentTransform.Value.localToWorldMatrix.MultiplyPoint3x4(headTransform.localPosition);
headTransform.rotation = parentTransform.Value.rotation * headTransform.localRotation;
headTransform = headTransform.UpdateParentMatrix(parentTransform.Value);
}
var currentTail = centerTransform.HasValue
? centerTransform.Value.localToWorldMatrix.MultiplyPoint3x4(CurrentTail[logicIndex])
? MathHelper.MultiplyPoint3x4(centerTransform.Value.localToWorldMatrix, CurrentTail[logicIndex])
: CurrentTail[logicIndex];
var prevTail = centerTransform.HasValue
? centerTransform.Value.localToWorldMatrix.MultiplyPoint3x4(PrevTail[logicIndex])
? MathHelper.MultiplyPoint3x4(centerTransform.Value.localToWorldMatrix, PrevTail[logicIndex])
: PrevTail[logicIndex];
var parentRotation = parentTransform?.rotation ?? Quaternion.identity;
var parentRotation = parentTransform?.rotation ?? quaternion.identity;
// scaling 対応
var scalingFactor = model.SupportsScalingAtRuntime ? TransformExtensions.AbsoluteMaxValue(headTransform.localToWorldMatrix.lossyScale) : 1.0f;
var scalingFactor = model.SupportsScalingAtRuntime ? math.cmax(math.abs(headTransform.lossyScale)) : 1.0f;
// verlet積分で次の位置を計算
var external = (joint.gravityDir * joint.gravityPower + model.ExternalForce) * DeltaTime;
var nextTail = currentTail
+ (currentTail - prevTail) * (1.0f - joint.dragForce) // 前フレームの移動を継続する(減衰もあるよ)
+ parentRotation * logic.localRotation * logic.boneAxis *
+ math.mul(math.mul(parentRotation, logic.localRotation), logic.boneAxis) *
joint.stiffnessForce * DeltaTime * scalingFactor // 親の回転による子ボーンの移動目標
+ external * scalingFactor; // 外力による移動量
// 長さをboneLengthに強制
nextTail = headTransform.position + (nextTail - headTransform.position).normalized * logic.length;
nextTail = headTransform.position + math.normalize(nextTail - headTransform.position) * logic.length;
nextTail = Anglelimit.Apply(logic, joint, parentRotation, head: headTransform.position, nextTail: nextTail);
// Collisionで移動
for (var colliderIndex = colliderSpan.startIndex; colliderIndex < colliderSpan.startIndex + colliderSpan.count; ++colliderIndex)
{
var collider = Colliders[colliderIndex];
var colliderTransform = Transforms[collider.transformIndex + transformIndexOffset];
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.tailOrNormal);
var colliderScale = colliderTransform.lossyScale;
var maxColliderScale = math.max(math.max(math.abs(colliderScale.x), math.abs(colliderScale.y)), math.abs(colliderScale.z));
var worldPosition = MathHelper.MultiplyPoint3x4(colliderTransform.localToWorldMatrix, collider.offset);
var worldTail = MathHelper.MultiplyPoint3x4(colliderTransform.localToWorldMatrix, collider.tailOrNormal);
switch (collider.colliderType)
if (SpringBoneCollision.TryCollide(logic, joint,
headTransform,
collider, colliderTransform, maxColliderScale,
colliderWorldTail: worldTail, colliderWorldPosition: worldPosition,
nextTail: nextTail,
out var newNextTail))
{
case BlittableColliderType.Sphere:
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, colliderTransform, ref nextTail);
break;
case BlittableColliderType.SphereInside:
ResolveSphereCollisionInside(joint, collider, colliderTransform, ref nextTail);
break;
case BlittableColliderType.CapsuleInside:
ResolveCapsuleCollisionInside(joint, collider, colliderTransform, ref nextTail);
break;
default:
throw new NotImplementedException();
// 衝突毎に nextTail を更新する。
nextTail = Anglelimit.Apply(logic, joint, parentRotation, head: headTransform.position, nextTail: newNextTail);
}
}
NextTail[logicIndex] = centerTransform.HasValue
? centerTransform.Value.worldToLocalMatrix.MultiplyPoint3x4(nextTail)
? MathHelper.MultiplyPoint3x4(centerTransform.Value.worldToLocalMatrix, nextTail)
: nextTail;
//回転を適用
var rotation = parentRotation * logic.localRotation;
headTransform.rotation = Quaternion.FromToRotation(rotation * logic.boneAxis,
nextTail - headTransform.position) * rotation;
// Transformを更新
if (parentTransform.HasValue)
{
var parentLocalToWorldMatrix = parentTransform.Value.localToWorldMatrix;
headTransform.localRotation = Normalize(Quaternion.Inverse(parentTransform.Value.rotation) * headTransform.rotation);
headTransform.localToWorldMatrix =
parentLocalToWorldMatrix *
Matrix4x4.TRS(
headTransform.localPosition,
headTransform.localRotation,
headTransform.localScale
);
headTransform.worldToLocalMatrix = headTransform.localToWorldMatrix.inverse;
}
else
{
headTransform.localToWorldMatrix =
Matrix4x4.TRS(
headTransform.position,
headTransform.rotation,
headTransform.localScale
);
headTransform.worldToLocalMatrix = headTransform.localToWorldMatrix.inverse;
headTransform.localRotation = headTransform.rotation;
}
var rotation = math.mul(parentRotation, logic.localRotation);
headTransform = headTransform.UpdateRotation(
math.mul(MathHelper.FromToRotation(math.mul(rotation, logic.boneAxis), nextTail - headTransform.position), rotation),
parentTransform);
if (!model.StopSpringBoneWriteback)
{
@ -180,161 +141,5 @@ namespace UniGLTF.SpringBoneJobs
}
}
/// <summary>
/// BurstではMathfがエラーを吐くため、内部でMathfを呼ばないNormalizeを自前実装
/// </summary>
private static Quaternion Normalize(Quaternion q)
{
var num = (float)Math.Sqrt(Quaternion.Dot(q, q));
return num < float.Epsilon ? Quaternion.identity : new Quaternion(q.x / num, q.y / num, q.z / num, q.w / num);
}
private static void ResolveCapsuleCollision(
Vector3 worldTail,
Vector3 worldPosition,
BlittableTransform headTransform,
BlittableJointMutable joint,
BlittableCollider collider,
float maxColliderScale,
BlittableJointImmutable logic,
ref Vector3 nextTail)
{
var direction = worldTail - worldPosition;
if (direction.sqrMagnitude == 0)
{
// head側半球の球判定
ResolveSphereCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail);
return;
}
var P = direction.normalized;
var Q = headTransform.position - worldPosition;
var dot = Vector3.Dot(P, Q);
if (dot <= 0)
{
// head側半球の球判定
ResolveSphereCollision(joint, collider, worldPosition, headTransform, maxColliderScale, logic, ref nextTail);
return;
}
if (dot >= direction.magnitude)
{
// tail側半球の球判定
ResolveSphereCollision(joint, collider, worldTail, headTransform, maxColliderScale, logic, ref nextTail);
return;
}
// head-tail上の m_transform.position との最近点
var p = worldPosition + P * dot;
ResolveSphereCollision(joint, collider, p, headTransform, maxColliderScale, logic, ref nextTail);
}
private static void ResolveSphereCollision(
BlittableJointMutable joint,
BlittableCollider collider,
Vector3 worldPosition,
BlittableTransform headTransform,
float maxColliderScale,
BlittableJointImmutable 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;
}
}
private static void ResolveSphereCollisionInside(
BlittableJointMutable joint,
BlittableCollider collider,
BlittableTransform colliderTransform,
ref Vector3 nextTail)
{
var transformedOffset = colliderTransform.localToWorldMatrix.MultiplyPoint(collider.offset);
var delta = nextTail - transformedOffset;
// ジョイントとコライダーの距離。負の値は衝突していることを示す
var distance = collider.radius - joint.radius - delta.magnitude;
// ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す
if (distance < 0)
{
var direction = -delta.normalized;
nextTail -= direction * distance;
}
}
private static void ResolveCapsuleCollisionInside(
BlittableJointMutable joint,
BlittableCollider collider,
BlittableTransform colliderTransform,
ref Vector3 nextTail)
{
var transformedOffset = colliderTransform.localToWorldMatrix.MultiplyPoint(collider.offset);
var transformedTail = colliderTransform.localToWorldMatrix.MultiplyPoint(collider.tailOrNormal);
var offsetToTail = transformedTail - transformedOffset;
var lengthSqCapsule = offsetToTail.sqrMagnitude;
var delta = nextTail - transformedOffset;
var dot = Vector3.Dot(offsetToTail, delta);
if (dot < 0.0)
{
// ジョイントがカプセルの始点側にある場合
// なにもしない
}
else if (dot > lengthSqCapsule)
{
// ジョイントがカプセルの終点側にある場合
delta -= offsetToTail;
}
else
{
// ジョイントがカプセルの始点と終点の間にある場合
delta -= offsetToTail * (dot / lengthSqCapsule);
}
// ジョイントとコライダーの距離。負の値は衝突していることを示す
var distance = collider.radius - joint.radius - delta.magnitude;
// ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す
if (distance < 0)
{
var direction = -delta.normalized;
nextTail -= direction * distance;
}
}
/// <summary>
/// Collision with SpringJoint and PlaneCollider.
/// If collide update nextTail.
/// </summary>
/// <param name="joint">joint</param>
/// <param name="collider">collier</param>
/// <param name="colliderTransform">colliderTransform.localToWorldMatrix.MultiplyPoint3x4(collider.offset);</param>
/// <param name="nextTail">result of verlet integration</param>
private static void ResolvePlaneCollision(
BlittableJointMutable joint,
BlittableCollider collider,
BlittableTransform colliderTransform,
ref Vector3 nextTail)
{
var transformedOffset = colliderTransform.localToWorldMatrix.MultiplyPoint(collider.offset);
var transformedNormal = colliderTransform.localToWorldMatrix.MultiplyVector(collider.tailOrNormal).normalized;
var delta = nextTail - transformedOffset;
// ジョイントとコライダーの距離。負の値は衝突していることを示す
var distance = Vector3.Dot(delta, transformedNormal) - joint.radius;
if (distance < 0)
{
// ジョイントとコライダーの距離の方向。衝突している場合、この方向にジョイントを押し出す
var direction = transformedNormal;
nextTail -= direction * distance;
}
}
}
}

View File

@ -0,0 +1,89 @@
using System.Runtime.CompilerServices;
using Unity.Mathematics;
namespace UniGLTF.Runtime.Utils
{
public static class MathHelper
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float3 MultiplyPoint3x4(float4x4 matrix, float3 point)
{
return math.mul(matrix, new float4(point, 1)).xyz;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float3 MultiplyPoint(float4x4 matrix, float3 point)
{
var v = math.mul(matrix, new float4(point, 1.0f));
return v.xyz / v.w;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float3 MultiplyVector(float4x4 matrix, float3 vector)
{
return math.mul(matrix, new float4(vector, 0)).xyz;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static quaternion FromToRotation(in float3 fromVector, in float3 toVector)
{
if (math.lengthsq(fromVector) == 0 || math.lengthsq(toVector) == 0)
{
return quaternion.identity;
}
float3 from = math.normalize(fromVector);
float3 to = math.normalize(toVector);
var dot = math.dot(from, to);
switch(dot)
{
case >= 1.0f:
return quaternion.identity;
case <= -1.0f:
{
var axis = math.cross(from, new float3(1, 0, 0));
if (math.lengthsq(axis) < 0.0001f)
{
axis = math.cross(from, new float3(0, 1, 0));
}
return quaternion.AxisAngle(math.normalize(axis), math.PI);
}
default:
{
var angle = math.acos(dot);
var axis = math.cross(from, to);
return quaternion.AxisAngle(math.normalize(axis), angle);
}
}
}
/// <summary>
/// <see cref="UnityEngine.Mathf.Approximately"/> を Unity.Mathematics パッケージ向けに再実装した関数
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
public static bool Approximately(float a, float b)
{
return math.abs(b - a) < math.max(1E-06f * math.max(math.abs(a), math.abs(b)), math.EPSILON * 8f);
}
/// <inheritdoc cref="MathHelper.Approximately(float, float)"/>
public static bool Approximately(float3 a, float3 b)
{
return Approximately(a.x, b.x) &&
Approximately(a.y, b.y) &&
Approximately(a.z, b.z);
}
/// <inheritdoc cref="MathHelper.Approximately(float, float)"/>
public static bool Approximately(quaternion a, quaternion b)
{
return Approximately(a.value.x, b.value.x) &&
Approximately(a.value.y, b.value.y) &&
Approximately(a.value.z, b.value.z) &&
Approximately(a.value.w, b.value.w);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 50ff9ccb88bd4c208ab432127ec7b04d
timeCreated: 1751330089

View File

@ -1,7 +1,9 @@
{
"name": "UniGLTF.Utils",
"rootNamespace": "",
"references": [],
"references": [
"GUID:d8b63aba1907145bea998dd612889d6b"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,

View File

@ -6,7 +6,8 @@
"GUID:5f875fdc81c40184c8333b9d63c6ddd5",
"GUID:27619889b8ba8c24980f49ee34dbb44a",
"GUID:0acc523941302664db1f4e527237feb3",
"GUID:1cd941934d098654fa21a13f28346412"
"GUID:1cd941934d098654fa21a13f28346412",
"GUID:d8b63aba1907145bea998dd612889d6b"
],
"includePlatforms": [
"Editor"

View File

@ -0,0 +1,49 @@
using NUnit.Framework;
using UniGLTF.Runtime.Utils;
using Unity.Mathematics;
using UnityEngine;
namespace UniGLTF
{
public class MathTests
{
private readonly float4x4 _matrix = new float4x4(
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14, 15, 16);
private readonly float3 _vector1 = new float3(1, 2, 3);
private readonly float3 _vector2 = new float3(4, 5, 6);
[Test]
public void MultiplyPoint3x4Test()
{
var result = MathHelper.MultiplyPoint3x4(_matrix, _vector1);
var expected = ((Matrix4x4)_matrix).MultiplyPoint3x4(_vector1);
Assert.That(MathHelper.Approximately(result, expected), Is.True);
}
[Test]
public void MultiplyPointTest()
{
var result = MathHelper.MultiplyPoint(_matrix, _vector1);
var expected = ((Matrix4x4)_matrix).MultiplyPoint(_vector1);
Assert.That(MathHelper.Approximately(result, expected), Is.True);
}
[Test]
public void MultiplyVectorTest()
{
var result = MathHelper.MultiplyVector(_matrix, _vector1);
var expected = ((Matrix4x4)_matrix).MultiplyVector(_vector1);
Assert.That(MathHelper.Approximately(result, expected), Is.True);
}
[Test]
public void FromToRotationTest()
{
var result = MathHelper.FromToRotation(_vector1, _vector2);
var expected = Quaternion.FromToRotation(_vector1, _vector2);
Assert.That(MathHelper.Approximately(result, expected), Is.True);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4b920c4a4ea1401085ba8923e4ccaca2
timeCreated: 1751329860

View File

@ -40,13 +40,10 @@ namespace VRM.SpringBoneJobs
var c = new FastSpringBoneCollider
{
Transform = group.transform,
Collider = new BlittableCollider
{
offset = collider.Offset,
radius = collider.Radius,
tailOrNormal = default,
colliderType = BlittableColliderType.Sphere
}
Collider = new BlittableCollider(
offset: collider.Offset,
radius: collider.Radius,
colliderType: BlittableColliderType.Sphere)
};
colliders.Add(c);
}
@ -85,14 +82,12 @@ namespace VRM.SpringBoneJobs
joints.Add(new FastSpringBoneJoint
{
Transform = joint,
Joint = new BlittableJointMutable
{
radius = spring.m_hitRadius,
dragForce = spring.m_dragForce,
gravityDir = spring.m_gravityDir,
gravityPower = spring.m_gravityPower,
stiffnessForce = spring.m_stiffnessForce
},
Joint = new BlittableJointMutable(
radius: spring.m_hitRadius,
dragForce: spring.m_dragForce,
gravityDir: spring.m_gravityDir,
gravityPower: spring.m_gravityPower,
stiffnessForce: spring.m_stiffnessForce),
DefaultLocalRotation = initMap[joint.transform].LocalRotation,
});
foreach (Transform child in joint)

View File

@ -7,7 +7,8 @@
"GUID:a9bc101fb0471f94a8f99fd242fdd934",
"GUID:1cd941934d098654fa21a13f28346412",
"GUID:60c8346e00a8ddd4cafc5a02eceeec57",
"GUID:3e5d614bc16b50d41bd94c8d7444ca46"
"GUID:3e5d614bc16b50d41bd94c8d7444ca46",
"GUID:d8b63aba1907145bea998dd612889d6b"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@ -8,11 +8,17 @@ namespace UniVRM10
class VRM10SpringBoneJointEditor : Editor
{
private VRM10SpringBoneJoint m_target;
private SerializedProperty m_script;
private SerializedProperty m_stiffnessForceProp;
private SerializedProperty m_gravityPowerProp;
private SerializedProperty m_gravityDirProp;
private SerializedProperty m_dragForceProp;
private SerializedProperty m_jointRadiusProp;
private SerializedProperty m_angleLimitType;
private SerializedProperty m_angleLimitRotation;
private SerializedProperty m_angleLimitAngle1;
private SerializedProperty m_angleLimitAngle2;
private Vrm10Instance m_root;
@ -24,11 +30,16 @@ namespace UniVRM10
}
m_target = (VRM10SpringBoneJoint)target;
m_script = serializedObject.FindProperty("m_Script");
m_stiffnessForceProp = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_stiffnessForce));
m_gravityPowerProp = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_gravityPower));
m_gravityDirProp = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_gravityDir));
m_dragForceProp = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_dragForce));
m_jointRadiusProp = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_jointRadius));
m_angleLimitType = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_anglelimitType));
m_angleLimitRotation = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_angleLimitRotation));
m_angleLimitAngle1 = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_angleLimitAngle1));
m_angleLimitAngle2 = serializedObject.FindProperty(nameof(VRM10SpringBoneJoint.m_angleLimitAngle2));
m_root = m_target.GetComponentInParent<Vrm10Instance>();
}
@ -36,9 +47,15 @@ namespace UniVRM10
static bool m_showJoints;
static bool m_showColliders;
static bool m_showJointSettings;
static bool m_showAnglelimitSettings;
public override void OnInspectorGUI()
{
using (new EditorGUI.DisabledScope(true))
{
EditorGUILayout.PropertyField(m_script);
}
serializedObject.Update();
///
@ -67,6 +84,36 @@ namespace UniVRM10
Vrm10EditorUtility.LimitBreakSlider(m_jointRadiusProp, 0.0f, 0.5f, 0.0f, Mathf.Infinity);
}
//
// angle limit
//
m_showAnglelimitSettings = EditorGUILayout.Foldout(m_showAnglelimitSettings, "AngleLimit Settings(dev)");
if (m_showAnglelimitSettings)
{
EditorGUILayout.PropertyField(m_angleLimitType);
switch ((UniGLTF.SpringBoneJobs.AnglelimitTypes)m_angleLimitType.enumValueIndex)
{
case UniGLTF.SpringBoneJobs.AnglelimitTypes.None:
break;
case UniGLTF.SpringBoneJobs.AnglelimitTypes.Cone:
EditorGUILayout.PropertyField(m_angleLimitRotation);
EditorGUILayout.PropertyField(m_angleLimitAngle1);
break;
case UniGLTF.SpringBoneJobs.AnglelimitTypes.Hinge:
EditorGUILayout.PropertyField(m_angleLimitRotation);
EditorGUILayout.PropertyField(m_angleLimitAngle1);
break;
case UniGLTF.SpringBoneJobs.AnglelimitTypes.Spherical:
EditorGUILayout.PropertyField(m_angleLimitRotation);
EditorGUILayout.PropertyField(m_angleLimitAngle1);
EditorGUILayout.PropertyField(m_angleLimitAngle2);
break;
}
}
if (serializedObject.ApplyModifiedProperties())
{
if (Application.isPlaying)

View File

@ -71,11 +71,6 @@ namespace UniVRM10
m_materialValueBindingMerger.AccumulateValue(clip, value);
}
public void RestoreMaterialInitialValues()
{
m_materialValueBindingMerger.RestoreMaterialInitialValues();
}
public void Dispose()
{
m_materialValueBindingMerger.Dispose();

View File

@ -138,17 +138,6 @@ namespace UniVRM10
}
}
}
/// <summary>
/// m_materialMap に記録した値に Material を復旧する
/// </summary>
public void RestoreMaterialInitialValues()
{
foreach (var kv in m_materialMap)
{
kv.Value.Clear();
}
}
#endregion
#region Accumulate

View File

@ -26,14 +26,38 @@ namespace UniVRM10
[SerializeField]
public float m_jointRadius = 0.02f;
public BlittableJointMutable Blittable => new BlittableJointMutable
[SerializeField]
public UniGLTF.SpringBoneJobs.AnglelimitTypes m_anglelimitType;
[SerializeField]
public Quaternion m_angleLimitRotation = Quaternion.identity;
[SerializeField, Range(0, Mathf.PI)]
public float m_angleLimitAngle1 = Mathf.PI;
[SerializeField, Range(0, Mathf.PI)]
public float m_angleLimitAngle2 = Mathf.PI;
public BlittableJointMutable Blittable => new BlittableJointMutable(
stiffnessForce: m_stiffnessForce,
gravityPower: m_gravityPower,
gravityDir: m_gravityDir,
dragForce: m_dragForce,
radius: m_jointRadius,
// v0.129.4
angleLimitType: (float)m_anglelimitType,
angleLimit1: m_angleLimitAngle1,
angleLimit2: m_angleLimitAngle2,
angleLimitOffset: m_angleLimitRotation
);
void OnValidate()
{
stiffnessForce = m_stiffnessForce,
dragForce = m_dragForce,
gravityDir = m_gravityDir,
gravityPower = m_gravityPower,
radius = m_jointRadius,
};
if (m_angleLimitRotation == default)
{
m_angleLimitRotation = Quaternion.identity;
}
}
void AddJointRecursive(Transform t, VRM10SpringBoneJoint src)
{

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d243bd3237701034a82757f58a0ec3da
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -49,26 +49,17 @@ namespace UniVRM10
.Select(collider => new FastSpringBoneCollider
{
Transform = collider.transform,
Collider = new BlittableCollider
{
offset = collider.Offset,
radius = collider.Radius,
tailOrNormal = collider.TailOrNormal,
colliderType = TranslateColliderType(collider.ColliderType)
}
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
},
Joint = joint.Blittable,
DefaultLocalRotation = GetOrAddDefaultTransformState(joint.transform).LocalRotation,
}).ToArray(),
}).ToArray();

View File

@ -43,7 +43,7 @@ namespace UniVRM10
/// <summary>
/// 毎フレーム Vrm10Runtime.Process から呼ばれる。
/// </summary>
public void Process();
public void Process(float deltaTime);
/// <summary>
/// from Vrm10Instance.OnDrawGizmosSelected

View File

@ -112,7 +112,7 @@ namespace UniVRM10
m_fastSpringBoneService.BufferCombiner.InitializeJointsLocalRotation(m_fastSpringBoneBuffer);
}
public void Process()
public void Process(float deltaTime)
{
// FastSpringBoneService が実行するので何もしない
}

View File

@ -118,9 +118,9 @@ namespace UniVRM10
m_bufferCombiner.InitializeJointsLocalRotation(m_fastSpringBoneBuffer);
}
public void Process()
public void Process(float deltaTime)
{
m_fastSpringBoneScheduler.Schedule(Time.deltaTime).Complete();
m_fastSpringBoneScheduler.Schedule(deltaTime).Complete();
}
public void DrawGizmos()

View File

@ -20,7 +20,7 @@ namespace UniVRM10
return Task.CompletedTask;
}
public void Process()
public void Process(float deltaTime)
{
}

View File

@ -156,7 +156,7 @@ namespace UniVRM10
Expression.Process(eyeDirection);
// 6. SpringBone
SpringBone.Process();
SpringBone.Process(Time.deltaTime);
}
}
}

View File

@ -51,14 +51,11 @@ namespace UniVRM10
public void Dispose()
{
_merger?.RestoreMaterialInitialValues();
_merger?.Dispose();
_merger = null;
_eyeDirectionApplicable?.Restore();
_eyeDirectionApplicable = null;
_merger?.Dispose();
_merger = null;
}
internal void Process(LookAtEyeDirection inputEyeDirection)

View File

@ -1,4 +1,5 @@
using UniGLTF.SpringBoneJobs;
using Unity.Jobs;
using UnityEngine;
namespace UniVRM10.FastSpringBones
@ -95,12 +96,17 @@ namespace UniVRM10.FastSpringBones
}
public void ManualUpdate(float deltaTime)
{
ManualUpdate(deltaTime, null).Complete();
}
public JobHandle ManualUpdate(in float deltaTime, in JobHandle? dependency = null)
{
if (UpdateType != UpdateTypes.Manual)
{
throw new global::System.ArgumentException("require UpdateTypes.Manual");
}
_fastSpringBoneScheduler.Schedule(deltaTime).Complete();
return _fastSpringBoneScheduler.Schedule(deltaTime, dependency);
}
public void OnDrawGizmosSelected()

View File

@ -8,6 +8,7 @@
"GUID:b7aa47b240b57de44a4b2021c143c9bf",
"GUID:f2ca1407928ebdc4bbe7765cc278be44",
"GUID:2665a8d13d1b3f18800f46e256720795",
"GUID:d8b63aba1907145bea998dd612889d6b",
"GUID:1cd941934d098654fa21a13f28346412",
"GUID:3e5d614bc16b50d41bd94c8d7444ca46",
"GUID:f06555f75b070af458a003d92f9efb00"

View File

@ -6,7 +6,8 @@
"GUID:e47c917724578cc43b5506c17a27e9a0",
"GUID:8d76e605759c3f64a957d63ef96ada7c",
"GUID:1cd941934d098654fa21a13f28346412",
"GUID:5f875fdc81c40184c8333b9d63c6ddd5"
"GUID:5f875fdc81c40184c8333b9d63c6ddd5",
"GUID:d8b63aba1907145bea998dd612889d6b"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@ -135,12 +135,7 @@ namespace UniVRM10.ClothWarp
// }
}
public void Process()
{
Process(Time.deltaTime);
}
void Process(float deltaTime)
public void Process(float deltaTime)
{
if (!_initialized)
{

View File

@ -193,14 +193,12 @@ namespace UniVRM10.ClothWarp.Jobs
var colliderTransformIndex = GetOrAddColliderTransform(collider.transform);
colliderRef.Add(colliderInfo.Count);
colliderInfo.Add(new BlittableCollider
{
offset = collider.Offset,
radius = collider.Radius,
tailOrNormal = collider.TailOrNormal,
colliderType = TranslateColliderType(collider.ColliderType),
transformIndex = colliderTransformIndex,
});
colliderInfo.Add(new BlittableCollider(
offset: collider.Offset,
radius: collider.Radius,
tailOrNormal: collider.TailOrNormal,
colliderType: TranslateColliderType(collider.ColliderType),
colliderTransformIndex: colliderTransformIndex));
_colliders.Add(collider);
}
@ -410,11 +408,6 @@ namespace UniVRM10.ClothWarp.Jobs
}
}
public void Process()
{
Process(Time.deltaTime);
}
public void Process(float deltaTime)
{
var frame = new FrameInfo(deltaTime, Vector3.zero);

View File

@ -39,14 +39,12 @@ namespace UniVRM10.ClothWarp.Jobs
public BlittableJointMutable ToBlittableJointMutable()
{
return new BlittableJointMutable
{
stiffnessForce = Stiffness,
gravityPower = 1.0f,
gravityDir = Gravity,
dragForce = Deceleration,
radius = Radius,
};
return new BlittableJointMutable(
stiffnessForce: Stiffness,
gravityPower: 1.0f,
gravityDir: Gravity,
dragForce: Deceleration,
radius: Radius);
}
}

View File

@ -185,15 +185,14 @@ namespace UniVRM10.VRM10Viewer
m_controller.ShowBoxMan(m_showBoxMan.value);
if (m_controller.TryUpdate(
m_motionMode.value == 0,
new BlittableModelLevel
{
ExternalForce = new Vector3(
new BlittableModelLevel(
externalForce: new Vector3(
m_springboneExternalX.value,
m_springboneExternalY.value,
m_springboneExternalZ.value),
StopSpringBoneWriteback = m_useSpringbonePause.value,
SupportsScalingAtRuntime = m_useSpringboneScaling.value,
},
stopSpringBoneWriteback: m_useSpringbonePause.value,
supportsScalingAtRuntime: m_useSpringboneScaling.value
),
out var loaded
))
{

View File

@ -7,7 +7,8 @@
"GUID:e47c917724578cc43b5506c17a27e9a0",
"GUID:1cd941934d098654fa21a13f28346412",
"GUID:3e5d614bc16b50d41bd94c8d7444ca46",
"GUID:f06555f75b070af458a003d92f9efb00"
"GUID:f06555f75b070af458a003d92f9efb00",
"GUID:d8b63aba1907145bea998dd612889d6b"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@ -226,12 +226,11 @@ namespace UniVRM10.VRM10Viewer
m_controller.ShowBoxMan(m_showBoxMan.isOn);
if (m_controller.TryUpdate(
m_ui.IsTPose,
new BlittableModelLevel
{
ExternalForce = new Vector3(m_springboneExternalX.value, m_springboneExternalY.value, m_springboneExternalZ.value),
StopSpringBoneWriteback = m_springbonePause.isOn,
SupportsScalingAtRuntime = m_springboneScaling.isOn,
},
new BlittableModelLevel(
externalForce: new Vector3(m_springboneExternalX.value, m_springboneExternalY.value, m_springboneExternalZ.value),
stopSpringBoneWriteback: m_springbonePause.isOn,
supportsScalingAtRuntime: m_springboneScaling.isOn
),
out var loaded
))
{

View File

@ -6,7 +6,8 @@
"GUID:1cd941934d098654fa21a13f28346412",
"GUID:b7aa47b240b57de44a4b2021c143c9bf",
"GUID:05dd262a0c0a2f841b8252c8c3815582",
"GUID:3e5d614bc16b50d41bd94c8d7444ca46"
"GUID:3e5d614bc16b50d41bd94c8d7444ca46",
"GUID:d8b63aba1907145bea998dd612889d6b"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@ -343,15 +343,15 @@ namespace VRM.SimpleViewer
m_loaded.EnableLipSyncValue = m_enableLipSync.isOn;
m_loaded.EnableBlinkValue = m_enableAutoBlink.isOn;
m_loaded.SetSpringboneModelLevel(new UniGLTF.SpringBoneJobs.Blittables.BlittableModelLevel
{
ExternalForce = new Vector3(
(
externalForce: new Vector3(
m_springExternalX.value,
m_springExternalY.value,
m_springExternalZ.value
),
StopSpringBoneWriteback = m_springBonePause.isOn,
SupportsScalingAtRuntime = m_springBoneScaling.isOn,
});
stopSpringBoneWriteback: m_springBonePause.isOn,
supportsScalingAtRuntime: m_springBoneScaling.isOn
));
m_loaded.Update();
}
}