mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2024-12-29 18:55:06 +08:00
[BoneProxy] feat: add support for keeping only one of world position/rotation
This commit is contained in:
parent
51f7c5936d
commit
eb7af61a08
61
Assets/_ModularAvatar/EditModeTests/BoneProxyTest.cs
Normal file
61
Assets/_ModularAvatar/EditModeTests/BoneProxyTest.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using nadena.dev.modular_avatar.core;
|
||||
using nadena.dev.modular_avatar.core.editor;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Internal;
|
||||
using UnityEngine;
|
||||
|
||||
namespace modular_avatar_tests
|
||||
{
|
||||
public class BoneProxyTest : TestBase
|
||||
{
|
||||
[Test]
|
||||
public void TestBoneProxy()
|
||||
{
|
||||
AssertAttachmentMode(BoneProxyAttachmentMode.AsChildAtRoot, expectSnapPos: true, expectSnapRot: true);
|
||||
AssertAttachmentMode(BoneProxyAttachmentMode.Unset, expectSnapPos: true, expectSnapRot: true);
|
||||
AssertAttachmentMode(BoneProxyAttachmentMode.AsChildKeepPosition, expectSnapPos: false,
|
||||
expectSnapRot: true);
|
||||
AssertAttachmentMode(BoneProxyAttachmentMode.AsChildKeepRotation, expectSnapPos: true,
|
||||
expectSnapRot: false);
|
||||
AssertAttachmentMode(BoneProxyAttachmentMode.AsChildKeepWorldPose, expectSnapPos: false,
|
||||
expectSnapRot: false);
|
||||
}
|
||||
|
||||
private void AssertAttachmentMode(BoneProxyAttachmentMode attachmentMode, bool expectSnapPos,
|
||||
bool expectSnapRot)
|
||||
{
|
||||
var root = CreateRoot("root");
|
||||
var bone = CreateChild(root, "bone");
|
||||
var proxy = CreateChild(root, "proxy");
|
||||
|
||||
var boneProxy = proxy.AddComponent<ModularAvatarBoneProxy>();
|
||||
boneProxy.target = bone.transform;
|
||||
boneProxy.attachmentMode = attachmentMode;
|
||||
|
||||
bone.transform.localPosition = Vector3.one;
|
||||
bone.transform.localRotation = Quaternion.Euler(123, 45, 6);
|
||||
|
||||
AvatarProcessor.ProcessAvatar(root);
|
||||
|
||||
Assert.AreEqual(proxy.transform.parent, bone.transform);
|
||||
|
||||
if (expectSnapPos)
|
||||
{
|
||||
Assert.LessOrEqual(Vector3.Distance(proxy.transform.localPosition, Vector3.zero), 0.0001f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.LessOrEqual(Vector3.Distance(proxy.transform.position, Vector3.zero), 0.0001f);
|
||||
}
|
||||
|
||||
if (expectSnapRot)
|
||||
{
|
||||
Assert.LessOrEqual(Quaternion.Angle(proxy.transform.localRotation, Quaternion.identity), 0.0001f);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.LessOrEqual(Quaternion.Angle(proxy.transform.rotation, Quaternion.identity), 0.0001f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0fe447e8f462493d91a53487af54f2b9
|
||||
timeCreated: 1673954075
|
320
Assets/_ModularAvatar/EditModeTests/MinimalAvatar.prefab
Normal file
320
Assets/_ModularAvatar/EditModeTests/MinimalAvatar.prefab
Normal file
@ -0,0 +1,320 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &6304364033355940381
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4805466113894723065}
|
||||
- component: {fileID: 7049391172907466529}
|
||||
- component: {fileID: 7355211162906115147}
|
||||
- component: {fileID: 515882129511000739}
|
||||
m_Layer: 0
|
||||
m_Name: MinimalAvatar
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &4805466113894723065
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6304364033355940381}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -0.9999927, y: -0.76461804, z: -2.4018843}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &7049391172907466529
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6304364033355940381}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
Name:
|
||||
ViewPosition: {x: 0, y: 1.6, z: 0.2}
|
||||
Animations: 0
|
||||
ScaleIPD: 1
|
||||
lipSync: 0
|
||||
lipSyncJawBone: {fileID: 0}
|
||||
lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1}
|
||||
lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1}
|
||||
VisemeSkinnedMesh: {fileID: 0}
|
||||
MouthOpenBlendShapeName: Facial_Blends.Jaw_Down
|
||||
VisemeBlendShapes: []
|
||||
unityVersion:
|
||||
portraitCameraPositionOffset: {x: 0, y: 0, z: 0}
|
||||
portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139}
|
||||
customExpressions: 0
|
||||
expressionsMenu: {fileID: 0}
|
||||
expressionParameters: {fileID: 0}
|
||||
enableEyeLook: 0
|
||||
customEyeLookSettings:
|
||||
eyeMovement:
|
||||
confidence: 0.5
|
||||
excitement: 0.5
|
||||
leftEye: {fileID: 0}
|
||||
rightEye: {fileID: 0}
|
||||
eyesLookingStraight:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
eyesLookingUp:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
eyesLookingDown:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
eyesLookingLeft:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
eyesLookingRight:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
eyelidType: 0
|
||||
upperLeftEyelid: {fileID: 0}
|
||||
upperRightEyelid: {fileID: 0}
|
||||
lowerLeftEyelid: {fileID: 0}
|
||||
lowerRightEyelid: {fileID: 0}
|
||||
eyelidsDefault:
|
||||
upper:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
lower:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
eyelidsClosed:
|
||||
upper:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
lower:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
eyelidsLookingUp:
|
||||
upper:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
lower:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
eyelidsLookingDown:
|
||||
upper:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
lower:
|
||||
linked: 1
|
||||
left: {x: 0, y: 0, z: 0, w: 0}
|
||||
right: {x: 0, y: 0, z: 0, w: 0}
|
||||
eyelidsSkinnedMesh: {fileID: 0}
|
||||
eyelidsBlendshapes:
|
||||
customizeAnimationLayers: 0
|
||||
baseAnimationLayers:
|
||||
- isEnabled: 0
|
||||
type: 0
|
||||
animatorController: {fileID: 0}
|
||||
mask: {fileID: 0}
|
||||
isDefault: 1
|
||||
- isEnabled: 0
|
||||
type: 4
|
||||
animatorController: {fileID: 0}
|
||||
mask: {fileID: 0}
|
||||
isDefault: 1
|
||||
- isEnabled: 0
|
||||
type: 5
|
||||
animatorController: {fileID: 0}
|
||||
mask: {fileID: 0}
|
||||
isDefault: 1
|
||||
specialAnimationLayers:
|
||||
- isEnabled: 0
|
||||
type: 6
|
||||
animatorController: {fileID: 0}
|
||||
mask: {fileID: 0}
|
||||
isDefault: 1
|
||||
- isEnabled: 0
|
||||
type: 7
|
||||
animatorController: {fileID: 0}
|
||||
mask: {fileID: 0}
|
||||
isDefault: 1
|
||||
- isEnabled: 0
|
||||
type: 8
|
||||
animatorController: {fileID: 0}
|
||||
mask: {fileID: 0}
|
||||
isDefault: 1
|
||||
AnimationPreset: {fileID: 0}
|
||||
animationHashSet: []
|
||||
autoFootsteps: 1
|
||||
autoLocomotion: 1
|
||||
collider_head:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_torso:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_footR:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_footL:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_handR:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_handL:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_fingerIndexL:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_fingerMiddleL:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_fingerRingL:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_fingerLittleL:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_fingerIndexR:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_fingerMiddleR:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_fingerRingR:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
collider_fingerLittleR:
|
||||
isMirrored: 1
|
||||
state: 0
|
||||
transform: {fileID: 0}
|
||||
radius: 0
|
||||
height: 0
|
||||
position: {x: 0, y: 0, z: 0}
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
--- !u!114 &7355211162906115147
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6304364033355940381}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
launchedFromSDKPipeline: 0
|
||||
completedSDKPipeline: 0
|
||||
blueprintId:
|
||||
contentType: 0
|
||||
assetBundleUnityVersion:
|
||||
fallbackStatus: 0
|
||||
--- !u!95 &515882129511000739
|
||||
Animator:
|
||||
serializedVersion: 3
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6304364033355940381}
|
||||
m_Enabled: 1
|
||||
m_Avatar: {fileID: 0}
|
||||
m_Controller: {fileID: 0}
|
||||
m_CullingMode: 0
|
||||
m_UpdateMode: 0
|
||||
m_ApplyRootMotion: 0
|
||||
m_LinearVelocityBlending: 0
|
||||
m_WarningMessage:
|
||||
m_HasTransformHierarchy: 1
|
||||
m_AllowConstantClipSamplingOptimization: 1
|
||||
m_KeepAnimatorControllerStateOnDisable: 0
|
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60d3416d1f6af4a47bf9056aefc38333
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -12,6 +12,7 @@ namespace modular_avatar_tests
|
||||
public class TestBase
|
||||
{
|
||||
private List<GameObject> objects;
|
||||
private const string MinimalAvatarGuid = "60d3416d1f6af4a47bf9056aefc38333";
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
@ -36,10 +37,10 @@ namespace modular_avatar_tests
|
||||
|
||||
protected GameObject CreateRoot(string name)
|
||||
{
|
||||
var go = new GameObject(name);
|
||||
var path = AssetDatabase.GUIDToAssetPath(MinimalAvatarGuid);
|
||||
var go = GameObject.Instantiate(AssetDatabase.LoadAssetAtPath<GameObject>(path));
|
||||
|
||||
objects.Add(go);
|
||||
// Needed for avatar path finding functions to work properly
|
||||
go.AddComponent(typeof(VRCAvatarDescriptor));
|
||||
return go;
|
||||
}
|
||||
|
||||
|
@ -46,11 +46,30 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
var oldPath = RuntimeUtil.AvatarRootPath(proxy.gameObject);
|
||||
Transform transform = proxy.transform;
|
||||
transform.SetParent(proxy.target, true);
|
||||
if (proxy.attachmentMode != BoneProxyAttachmentMode.AsChildKeepWorldPosition)
|
||||
|
||||
bool keepPos, keepRot;
|
||||
switch (proxy.attachmentMode)
|
||||
{
|
||||
transform.localPosition = Vector3.zero;
|
||||
transform.localRotation = Quaternion.identity;
|
||||
default:
|
||||
case BoneProxyAttachmentMode.Unset:
|
||||
case BoneProxyAttachmentMode.AsChildAtRoot:
|
||||
keepPos = keepRot = false;
|
||||
break;
|
||||
case BoneProxyAttachmentMode.AsChildKeepWorldPose:
|
||||
keepPos = keepRot = true;
|
||||
break;
|
||||
case BoneProxyAttachmentMode.AsChildKeepPosition:
|
||||
keepPos = true;
|
||||
keepRot = false;
|
||||
break;
|
||||
case BoneProxyAttachmentMode.AsChildKeepRotation:
|
||||
keepRot = true;
|
||||
keepPos = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!keepPos) transform.localPosition = Vector3.zero;
|
||||
if (!keepRot) transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
|
||||
Object.DestroyImmediate(proxy);
|
||||
|
@ -17,7 +17,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
protected override string localizationPrefix => "boneproxy.attachment";
|
||||
|
||||
protected override Array enumValues => new object[]
|
||||
{BoneProxyAttachmentMode.AsChildAtRoot, BoneProxyAttachmentMode.AsChildKeepWorldPosition};
|
||||
{BoneProxyAttachmentMode.AsChildAtRoot, BoneProxyAttachmentMode.AsChildKeepWorldPose};
|
||||
}
|
||||
|
||||
[CustomEditor(typeof(ModularAvatarBoneProxy))]
|
||||
@ -130,7 +130,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
Undo.RecordObject(boneProxy, "Configuring bone proxy attachment mode");
|
||||
if (posDelta > 0.001f || rotDelta > 0.001f)
|
||||
{
|
||||
boneProxy.attachmentMode = BoneProxyAttachmentMode.AsChildKeepWorldPosition;
|
||||
boneProxy.attachmentMode = BoneProxyAttachmentMode.AsChildKeepWorldPose;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -56,7 +56,9 @@
|
||||
"boneproxy.err.NotInAvatar": "You must specify an object that is in the avatar",
|
||||
"boneproxy.attachment": "Attachment mode",
|
||||
"boneproxy.attachment.AsChildAtRoot": "As child; at root",
|
||||
"boneproxy.attachment.AsChildKeepWorldPose": "As child; keep position and rotation",
|
||||
"boneproxy.attachment.AsChildKeepWorldPosition": "As child; keep position",
|
||||
"boneproxy.attachment.AsChildKeepWorldRotation": "As child; keep rotation",
|
||||
"pb_blocker.help": "This object will not be affected by PhysBones attached to parents.",
|
||||
"hint.bad_vrcsdk": "Incompatible version of VRCSDK detected.\n\nPlease try upgrading your VRCSDK; if this does not work, check for a newer version of Modular Avatar as well."
|
||||
}
|
@ -54,7 +54,9 @@
|
||||
"boneproxy.err.NotInAvatar": "アバター内のオブジェクトを指定してください。",
|
||||
"boneproxy.attachment": "配置モード",
|
||||
"boneproxy.attachment.AsChildAtRoot": "子として・ルートに配置",
|
||||
"boneproxy.attachment.AsChildKeepWorldPose": "子として・ワールド位置と向きを維持",
|
||||
"boneproxy.attachment.AsChildKeepWorldPosition": "子として・ワールド位置を維持",
|
||||
"boneproxy.attachment.AsChildKeepWorldRotation": "子として・ワールド向きを維持",
|
||||
"pb_blocker.help": "このオブジェクトは親のPhysBoneから影響を受けなくなります。",
|
||||
"hint.bad_vrcsdk": "使用中のVRCSDKのバージョンとは互換性がありません。\n\nVRCSDKを更新してみてください。それでもだめでしたら、Modular Avatarにも最新版が出てないかチェックしてください。"
|
||||
}
|
||||
|
@ -59,8 +59,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
var descriptor = avatarGameObject.GetComponent<VRCAvatarDescriptor>();
|
||||
|
||||
InitSessions(descriptor.baseAnimationLayers);
|
||||
InitSessions(descriptor.specialAnimationLayers);
|
||||
if (descriptor.baseAnimationLayers != null) InitSessions(descriptor.baseAnimationLayers);
|
||||
if (descriptor.specialAnimationLayers != null) InitSessions(descriptor.specialAnimationLayers);
|
||||
|
||||
var toMerge = avatarGameObject.transform.GetComponentsInChildren<ModularAvatarMergeAnimator>(true);
|
||||
|
||||
|
@ -46,7 +46,17 @@ namespace nadena.dev.modular_avatar.core
|
||||
/// <summary>
|
||||
/// Places the bone proxy object at the target, preserving world position and orientation.
|
||||
/// </summary>
|
||||
AsChildKeepWorldPosition,
|
||||
AsChildKeepWorldPose,
|
||||
|
||||
/// <summary>
|
||||
/// Places the bone proxy object at the target, preserving local rotation only.
|
||||
/// </summary>
|
||||
AsChildKeepRotation,
|
||||
|
||||
/// <summary>
|
||||
/// Places the bone proxy object at the target, preserving local position only.
|
||||
/// </summary>
|
||||
AsChildKeepPosition,
|
||||
}
|
||||
|
||||
[ExecuteInEditMode]
|
||||
|
@ -36,9 +36,12 @@ In the "As child at root" attachment mode, the object that the bone proxy is att
|
||||
its local position and orientation will be zeroed out. This will place it at the same position and orientation as the target object.
|
||||
This mode is recommended for prefabs that are not avatar-specific.
|
||||
|
||||
In the "As child keep world position" attachment mode, the object that the bone proxy is attached to will be reparented to the target object,
|
||||
In the "As child keep world pose" attachment mode, the object that the bone proxy is attached to will be reparented to the target object,
|
||||
but its world position and orientation will be preserved. This is usually only useful for avatar-specific prefabs, where you want to
|
||||
place an object at a precise position relative to the parent bone. For example, it can be used to place colliders for cloth components.
|
||||
|
||||
You can also opt to keep only one of the original position or rotation, allowing the other to match the target bone. This can sometimes
|
||||
be useful for more advanced applications.
|
||||
|
||||
When you set the target for a bone proxy component, the attachment mode will be automatically set based on whether the object is
|
||||
currently at the target bone's position and orientation.
|
@ -34,7 +34,9 @@ Bone Proxyコンポーネントをプレハブの中のオブジェクトに追
|
||||
「子として・ルートに配置」の設定では、Bone Proxyがアタッチされているオブジェクトがターゲットのオブジェクトの子になり、
|
||||
位置や姿勢がその親と同じになります。アバターに依存しないプレハブに推奨されます。サンプルのClapやFingerpenもこのモードです。
|
||||
|
||||
「子として・ワールド位置を維持」の設定では、Bone Proxyがアタッチされているオブジェクトがターゲットのオブジェクトの子になりますが、
|
||||
「子として・ワールド位置と向きを維持」の設定では、Bone Proxyがアタッチされているオブジェクトがターゲットのオブジェクトの子になりますが、
|
||||
位置や姿勢がワールド座標で維持されます。このモードはアバターに依存してしまうが、例えばClothコライダーの配置などに便利かもしれません。
|
||||
|
||||
位置・向きの片方だけ元のままにして、もう片方をボーンに合わせることも可能です。複雑なギミックを作るときに役立つ場合もあるかもしれません。
|
||||
|
||||
Bone Proxyのターゲットを設定する時は、ターゲットとの相互位置や姿勢を参考に、配置モードが設定されていない場合は自動的に設定されます。
|
Loading…
Reference in New Issue
Block a user