mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-01-17 11:50:11 +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
|
public class TestBase
|
||||||
{
|
{
|
||||||
private List<GameObject> objects;
|
private List<GameObject> objects;
|
||||||
|
private const string MinimalAvatarGuid = "60d3416d1f6af4a47bf9056aefc38333";
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
@ -36,10 +37,10 @@ namespace modular_avatar_tests
|
|||||||
|
|
||||||
protected GameObject CreateRoot(string name)
|
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);
|
objects.Add(go);
|
||||||
// Needed for avatar path finding functions to work properly
|
|
||||||
go.AddComponent(typeof(VRCAvatarDescriptor));
|
|
||||||
return go;
|
return go;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,11 +46,30 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
var oldPath = RuntimeUtil.AvatarRootPath(proxy.gameObject);
|
var oldPath = RuntimeUtil.AvatarRootPath(proxy.gameObject);
|
||||||
Transform transform = proxy.transform;
|
Transform transform = proxy.transform;
|
||||||
transform.SetParent(proxy.target, true);
|
transform.SetParent(proxy.target, true);
|
||||||
if (proxy.attachmentMode != BoneProxyAttachmentMode.AsChildKeepWorldPosition)
|
|
||||||
|
bool keepPos, keepRot;
|
||||||
|
switch (proxy.attachmentMode)
|
||||||
{
|
{
|
||||||
transform.localPosition = Vector3.zero;
|
default:
|
||||||
transform.localRotation = Quaternion.identity;
|
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);
|
Object.DestroyImmediate(proxy);
|
||||||
|
@ -17,7 +17,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
protected override string localizationPrefix => "boneproxy.attachment";
|
protected override string localizationPrefix => "boneproxy.attachment";
|
||||||
|
|
||||||
protected override Array enumValues => new object[]
|
protected override Array enumValues => new object[]
|
||||||
{BoneProxyAttachmentMode.AsChildAtRoot, BoneProxyAttachmentMode.AsChildKeepWorldPosition};
|
{BoneProxyAttachmentMode.AsChildAtRoot, BoneProxyAttachmentMode.AsChildKeepWorldPose};
|
||||||
}
|
}
|
||||||
|
|
||||||
[CustomEditor(typeof(ModularAvatarBoneProxy))]
|
[CustomEditor(typeof(ModularAvatarBoneProxy))]
|
||||||
@ -130,7 +130,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
Undo.RecordObject(boneProxy, "Configuring bone proxy attachment mode");
|
Undo.RecordObject(boneProxy, "Configuring bone proxy attachment mode");
|
||||||
if (posDelta > 0.001f || rotDelta > 0.001f)
|
if (posDelta > 0.001f || rotDelta > 0.001f)
|
||||||
{
|
{
|
||||||
boneProxy.attachmentMode = BoneProxyAttachmentMode.AsChildKeepWorldPosition;
|
boneProxy.attachmentMode = BoneProxyAttachmentMode.AsChildKeepWorldPose;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -56,7 +56,9 @@
|
|||||||
"boneproxy.err.NotInAvatar": "You must specify an object that is in the avatar",
|
"boneproxy.err.NotInAvatar": "You must specify an object that is in the avatar",
|
||||||
"boneproxy.attachment": "Attachment mode",
|
"boneproxy.attachment": "Attachment mode",
|
||||||
"boneproxy.attachment.AsChildAtRoot": "As child; at root",
|
"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.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.",
|
"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."
|
"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.err.NotInAvatar": "アバター内のオブジェクトを指定してください。",
|
||||||
"boneproxy.attachment": "配置モード",
|
"boneproxy.attachment": "配置モード",
|
||||||
"boneproxy.attachment.AsChildAtRoot": "子として・ルートに配置",
|
"boneproxy.attachment.AsChildAtRoot": "子として・ルートに配置",
|
||||||
|
"boneproxy.attachment.AsChildKeepWorldPose": "子として・ワールド位置と向きを維持",
|
||||||
"boneproxy.attachment.AsChildKeepWorldPosition": "子として・ワールド位置を維持",
|
"boneproxy.attachment.AsChildKeepWorldPosition": "子として・ワールド位置を維持",
|
||||||
|
"boneproxy.attachment.AsChildKeepWorldRotation": "子として・ワールド向きを維持",
|
||||||
"pb_blocker.help": "このオブジェクトは親のPhysBoneから影響を受けなくなります。",
|
"pb_blocker.help": "このオブジェクトは親のPhysBoneから影響を受けなくなります。",
|
||||||
"hint.bad_vrcsdk": "使用中のVRCSDKのバージョンとは互換性がありません。\n\nVRCSDKを更新してみてください。それでもだめでしたら、Modular Avatarにも最新版が出てないかチェックしてください。"
|
"hint.bad_vrcsdk": "使用中のVRCSDKのバージョンとは互換性がありません。\n\nVRCSDKを更新してみてください。それでもだめでしたら、Modular Avatarにも最新版が出てないかチェックしてください。"
|
||||||
}
|
}
|
||||||
|
@ -59,8 +59,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
var descriptor = avatarGameObject.GetComponent<VRCAvatarDescriptor>();
|
var descriptor = avatarGameObject.GetComponent<VRCAvatarDescriptor>();
|
||||||
|
|
||||||
InitSessions(descriptor.baseAnimationLayers);
|
if (descriptor.baseAnimationLayers != null) InitSessions(descriptor.baseAnimationLayers);
|
||||||
InitSessions(descriptor.specialAnimationLayers);
|
if (descriptor.specialAnimationLayers != null) InitSessions(descriptor.specialAnimationLayers);
|
||||||
|
|
||||||
var toMerge = avatarGameObject.transform.GetComponentsInChildren<ModularAvatarMergeAnimator>(true);
|
var toMerge = avatarGameObject.transform.GetComponentsInChildren<ModularAvatarMergeAnimator>(true);
|
||||||
|
|
||||||
|
@ -46,7 +46,17 @@ namespace nadena.dev.modular_avatar.core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Places the bone proxy object at the target, preserving world position and orientation.
|
/// Places the bone proxy object at the target, preserving world position and orientation.
|
||||||
/// </summary>
|
/// </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]
|
[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.
|
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.
|
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
|
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.
|
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
|
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.
|
currently at the target bone's position and orientation.
|
@ -34,7 +34,9 @@ Bone Proxyコンポーネントをプレハブの中のオブジェクトに追
|
|||||||
「子として・ルートに配置」の設定では、Bone Proxyがアタッチされているオブジェクトがターゲットのオブジェクトの子になり、
|
「子として・ルートに配置」の設定では、Bone Proxyがアタッチされているオブジェクトがターゲットのオブジェクトの子になり、
|
||||||
位置や姿勢がその親と同じになります。アバターに依存しないプレハブに推奨されます。サンプルのClapやFingerpenもこのモードです。
|
位置や姿勢がその親と同じになります。アバターに依存しないプレハブに推奨されます。サンプルのClapやFingerpenもこのモードです。
|
||||||
|
|
||||||
「子として・ワールド位置を維持」の設定では、Bone Proxyがアタッチされているオブジェクトがターゲットのオブジェクトの子になりますが、
|
「子として・ワールド位置と向きを維持」の設定では、Bone Proxyがアタッチされているオブジェクトがターゲットのオブジェクトの子になりますが、
|
||||||
位置や姿勢がワールド座標で維持されます。このモードはアバターに依存してしまうが、例えばClothコライダーの配置などに便利かもしれません。
|
位置や姿勢がワールド座標で維持されます。このモードはアバターに依存してしまうが、例えばClothコライダーの配置などに便利かもしれません。
|
||||||
|
|
||||||
|
位置・向きの片方だけ元のままにして、もう片方をボーンに合わせることも可能です。複雑なギミックを作るときに役立つ場合もあるかもしれません。
|
||||||
|
|
||||||
Bone Proxyのターゲットを設定する時は、ターゲットとの相互位置や姿勢を参考に、配置モードが設定されていない場合は自動的に設定されます。
|
Bone Proxyのターゲットを設定する時は、ターゲットとの相互位置や姿勢を参考に、配置モードが設定されていない場合は自動的に設定されます。
|
Loading…
Reference in New Issue
Block a user