impl Vrm10RuntimeSpringBone.RestoreInitialTransform

This commit is contained in:
ousttrue
2024-07-17 14:42:58 +09:00
parent b69b3760e3
commit a9d645d4ff
4 changed files with 332 additions and 68 deletions

View File

@@ -139,5 +139,24 @@ namespace UniVRM10
throw new ArgumentOutOfRangeException();
}
}
public void RestoreInitialTransform()
{
// Spring の joint に対応する transform の回転を初期状態
foreach (var (k, v) in m_initialData.TransformIndexMap)
{
k.localRotation = v.InitialLocalRotation;
}
// 初期状態にしたtransformを使って spring logic を構築
m_initialData.BlittableLogics.Clear();
foreach (var spring in m_initialData.Springs)
{
m_initialData.AddLogic(spring);
}
// DOTS バッファーを更新
m_initialData.SyncAndZeroVelocity(m_fastSpringBoneBuffer.Logics);
}
}
}

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Profiling;
using UniVRM10.FastSpringBones.Blittables;
@@ -13,9 +14,17 @@ namespace UniVRM10.FastSpringBones.System
public readonly List<BlittableCollider> BlittableColliders = new();
public readonly List<BlittableLogic> BlittableLogics = new();
public readonly Transform[] Transforms;
public FastSpringBoneBufferBuilder(IReadOnlyList<FastSpringBoneSpring> springs, bool simulateLastBone = false)
public struct TransformInfo
{
public int Index;
public Quaternion InitialLocalRotation;
}
public readonly IDictionary<Transform, TransformInfo> TransformIndexMap;
public readonly FastSpringBoneSpring[] Springs;
public FastSpringBoneBufferBuilder(FastSpringBoneSpring[] springs, bool simulateLastBone = false)
{
Springs = springs;
Profiler.BeginSample("FastSpringBone.ConstructBuffers.BufferBuilder");
var transformHashSet = new HashSet<Transform>();
foreach (var spring in springs)
@@ -34,8 +43,12 @@ namespace UniVRM10.FastSpringBones.System
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);
TransformIndexMap = Transforms.Select((trs, index) => (trs, index))
.ToDictionary(tuple => tuple.trs, tuple => new TransformInfo
{
Index = tuple.index,
InitialLocalRotation = tuple.trs.localRotation,
});
foreach (var spring in springs)
{
@@ -51,14 +64,14 @@ namespace UniVRM10.FastSpringBones.System
startIndex = BlittableJoints.Count,
count = simulateLastBone ? spring.joints.Length : spring.joints.Length - 1,
},
centerTransformIndex = spring.center ? transformIndexDictionary[spring.center] : -1,
centerTransformIndex = spring.center ? TransformIndexMap[spring.center].Index : -1,
};
BlittableSprings.Add(blittableSpring);
BlittableColliders.AddRange(spring.colliders.Select(collider =>
{
var blittable = collider.Collider;
blittable.transformIndex = transformIndexDictionary[collider.Transform];
blittable.transformIndex = TransformIndexMap[collider.Transform].Index;
return blittable;
}));
BlittableJoints.AddRange(spring.joints
@@ -68,56 +81,62 @@ namespace UniVRM10.FastSpringBones.System
return blittable;
}));
for (var i = 0; i < (simulateLastBone ? spring.joints.Length : spring.joints.Length - 1); ++i)
AddLogic(spring, simulateLastBone);
}
Profiler.EndSample();
}
public void AddLogic(FastSpringBoneSpring spring, bool simulateLastBone = false)
{
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)
{
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)
{
localPosition = tailJoint.Value.Transform.localPosition;
var delta = joint.Transform.position - parentJoint.Value.Transform.position;
localPosition =
joint.Transform.worldToLocalMatrix.MultiplyPoint(joint.Transform.position + delta);
}
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;
}
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
});
}
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 = TransformIndexMap[joint.Transform].Index,
parentTransformIndex = parent != null ? TransformIndexMap[parent].Index : -1,
currentTail = currentTail,
prevTail = currentTail,
localRotation = joint.DefaultLocalRotation,
boneAxis = localChildPosition.normalized,
length = localChildPosition.magnitude
});
}
Profiler.EndSample();
}
public unsafe void SetExternalDataPtr(BlittableExternalData* externalData)
@@ -129,14 +148,18 @@ namespace UniVRM10.FastSpringBones.System
// ExternalData = externalData,
// };
var b = BlittableSprings[i];
BlittableSprings[i] = new BlittableSpring
{
centerTransformIndex = b.centerTransformIndex,
colliderSpan = b.colliderSpan,
logicSpan = b.logicSpan,
transformIndexOffset = b.transformIndexOffset,
ExternalData = externalData,
};
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

@@ -232,7 +232,7 @@ RectTransform:
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 339774397}
m_RootOrder: 15
m_RootOrder: 16
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
@@ -773,7 +773,7 @@ RectTransform:
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 339774397}
m_RootOrder: 4
m_RootOrder: 3
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
@@ -1236,14 +1236,15 @@ RectTransform:
- {fileID: 1621794411}
- {fileID: 2009818432}
- {fileID: 168425995}
- {fileID: 1307084561}
- {fileID: 224350191}
- {fileID: 1791103379}
- {fileID: 1311520909}
- {fileID: 1307084561}
- {fileID: 974864191}
- {fileID: 1767706907}
- {fileID: 1557052150}
- {fileID: 1728528388}
- {fileID: 704896193}
- {fileID: 597950322}
- {fileID: 935566651}
- {fileID: 634488421}
@@ -1823,7 +1824,7 @@ RectTransform:
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 339774397}
m_RootOrder: 11
m_RootOrder: 12
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
@@ -1904,7 +1905,7 @@ RectTransform:
- {fileID: 154330168}
- {fileID: 1954133885}
m_Father: {fileID: 339774397}
m_RootOrder: 17
m_RootOrder: 18
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
@@ -1991,7 +1992,7 @@ RectTransform:
- {fileID: 2010083454}
- {fileID: 1081455630}
m_Father: {fileID: 339774397}
m_RootOrder: 13
m_RootOrder: 14
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
@@ -2247,6 +2248,128 @@ MonoBehaviour:
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
m_ReverseArrangement: 0
--- !u!1 &704896192
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 704896193}
- component: {fileID: 704896196}
- component: {fileID: 704896195}
- component: {fileID: 704896194}
m_Layer: 5
m_Name: ResetSpringBone
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &704896193
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 704896192}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 983782643}
m_Father: {fileID: 339774397}
m_RootOrder: 11
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 162, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &704896194
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 704896192}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Highlighted
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 704896195}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!114 &704896195
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 704896192}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &704896196
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 704896192}
m_CullTransparentMesh: 0
--- !u!1 &773923918
GameObject:
m_ObjectHideFlags: 0
@@ -3398,7 +3521,7 @@ RectTransform:
- {fileID: 175751363}
- {fileID: 1904789319}
m_Father: {fileID: 339774397}
m_RootOrder: 12
m_RootOrder: 13
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
@@ -3485,6 +3608,88 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 974864190}
m_CullTransparentMesh: 0
--- !u!1 &983782642
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 983782643}
- component: {fileID: 983782645}
- component: {fileID: 983782644}
m_Layer: 5
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &983782643
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 983782642}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 704896193}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &983782644
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 983782642}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 14
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 10
m_MaxSize: 40
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: 'ResetSpring
'
--- !u!222 &983782645
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 983782642}
m_CullTransparentMesh: 0
--- !u!1 &1007924635
GameObject:
m_ObjectHideFlags: 0
@@ -4950,7 +5155,7 @@ RectTransform:
m_Children:
- {fileID: 910859648}
m_Father: {fileID: 339774397}
m_RootOrder: 3
m_RootOrder: 6
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
@@ -5147,7 +5352,7 @@ RectTransform:
- {fileID: 1866921958}
- {fileID: 1767669911}
m_Father: {fileID: 339774397}
m_RootOrder: 6
m_RootOrder: 5
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
@@ -5444,7 +5649,7 @@ RectTransform:
- {fileID: 452923209}
- {fileID: 2090837017}
m_Father: {fileID: 339774397}
m_RootOrder: 16
m_RootOrder: 17
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
@@ -6444,7 +6649,7 @@ RectTransform:
- {fileID: 62367395}
- {fileID: 1037763549}
m_Father: {fileID: 339774397}
m_RootOrder: 14
m_RootOrder: 15
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
@@ -6619,6 +6824,7 @@ MonoBehaviour:
m_pastePose: {fileID: 1307084564}
m_showBoxMan: {fileID: 1767706908}
m_pauseSpringBone: {fileID: 1728528389}
m_resetSpringBone: {fileID: 704896194}
m_enableLipSync: {fileID: 935566650}
m_enableAutoBlink: {fileID: 634488422}
m_enableAutoExpression: {fileID: 1767738855}
@@ -6677,7 +6883,7 @@ RectTransform:
- {fileID: 1166391799}
- {fileID: 1140410864}
m_Father: {fileID: 339774397}
m_RootOrder: 5
m_RootOrder: 4
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}

View File

@@ -30,6 +30,9 @@ namespace UniVRM10.VRM10Viewer
[SerializeField]
Toggle m_pauseSpringBone = default;
[SerializeField]
Button m_resetSpringBone = default;
[SerializeField]
Toggle m_enableLipSync = default;
@@ -255,6 +258,7 @@ namespace UniVRM10.VRM10Viewer
m_openModel = buttons.First(x => x.name == "OpenModel");
m_openMotion = buttons.First(x => x.name == "OpenMotion");
m_pastePose = buttons.First(x => x.name == "PastePose");
m_resetSpringBone = buttons.First(x => x.name == "ResetSpringBone");
#if UNITY_2022_3_OR_NEWER
var toggles = GameObject.FindObjectsByType<Toggle>(FindObjectsSortMode.InstanceID);
@@ -351,6 +355,7 @@ namespace UniVRM10.VRM10Viewer
m_openModel.onClick.AddListener(OnOpenModelClicked);
m_openMotion.onClick.AddListener(OnOpenMotionClicked);
m_pastePose.onClick.AddListener(OnPastePoseClicked);
m_resetSpringBone.onClick.AddListener(OnResetSpringBoneClicked);
// load initial bvh
if (m_motion != null)
@@ -490,6 +495,17 @@ namespace UniVRM10.VRM10Viewer
}
}
void OnResetSpringBoneClicked()
{
if (m_loaded != null)
{
if (m_loaded.Runtime != null)
{
m_loaded.Runtime.SpringBone.RestoreInitialTransform();
}
}
}
static IMaterialDescriptorGenerator GetVrmMaterialDescriptorGenerator(bool useUrp)
{
if (useUrp)