diff --git a/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs b/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs index f701b240..18e10bbf 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/AvatarProcessor.cs @@ -145,6 +145,7 @@ namespace nadena.dev.modular_avatar.core.editor new VisibleHeadAccessoryProcessor(avatarGameObject.GetComponent()).Process(); new MergeAnimatorProcessor().OnPreprocessAvatar(avatarGameObject); new BlendshapeSyncAnimationProcessor().OnPreprocessAvatar(avatarGameObject); + PhysboneBlockerPass.Process(avatarGameObject); AfterProcessing?.Invoke(avatarGameObject); } diff --git a/Packages/nadena.dev.modular-avatar/Editor/Inspector/PBBlockerEditor.cs b/Packages/nadena.dev.modular-avatar/Editor/Inspector/PBBlockerEditor.cs new file mode 100644 index 00000000..ca43a9b9 --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Editor/Inspector/PBBlockerEditor.cs @@ -0,0 +1,40 @@ +/* + * MIT License + * + * Copyright (c) 2022 bd_ + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using UnityEditor; + +namespace nadena.dev.modular_avatar.core.editor +{ + [CustomEditor(typeof(ModularAvatarPBBlocker))] + [CanEditMultipleObjects] + internal class PBBlockerEditor : MAEditorBase + { + protected override void OnInnerInspectorGUI() + { + EditorGUILayout.HelpBox(Localization.S("pb_blocker.help"), MessageType.Info); + + Localization.ShowLanguageUI(); + } + } +} \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Editor/Inspector/PBBlockerEditor.cs.meta b/Packages/nadena.dev.modular-avatar/Editor/Inspector/PBBlockerEditor.cs.meta new file mode 100644 index 00000000..e5f41e49 --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Editor/Inspector/PBBlockerEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ebb82fd864d647a893f9a5c1dee80703 +timeCreated: 1669750103 \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Editor/Localization/en.json b/Packages/nadena.dev.modular-avatar/Editor/Localization/en.json index bfc70e52..64ef7078 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/Localization/en.json +++ b/Packages/nadena.dev.modular-avatar/Editor/Localization/en.json @@ -50,5 +50,6 @@ "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.AsChildKeepWorldPosition": "As child; keep position" + "boneproxy.attachment.AsChildKeepWorldPosition": "As child; keep position", + "pb_blocker.help": "This object will not be affected by PhysBones attached to parents." } \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Editor/Localization/ja.json b/Packages/nadena.dev.modular-avatar/Editor/Localization/ja.json index 7a5d1088..ffd5693d 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/Localization/ja.json +++ b/Packages/nadena.dev.modular-avatar/Editor/Localization/ja.json @@ -50,5 +50,6 @@ "boneproxy.err.NotInAvatar": "アバター内のオブジェクトを指定してください。", "boneproxy.attachment": "配置モード", "boneproxy.attachment.AsChildAtRoot": "子として・ルートに配置", - "boneproxy.attachment.AsChildKeepWorldPosition": "子として・ワールド位置を維持" + "boneproxy.attachment.AsChildKeepWorldPosition": "子として・ワールド位置を維持", + "pb_blocker.help": "このオブジェクトは親のPhysBoneから影響を受けなくなります。" } \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Editor/PhysboneBlockerPass.cs b/Packages/nadena.dev.modular-avatar/Editor/PhysboneBlockerPass.cs new file mode 100644 index 00000000..bd152db7 --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Editor/PhysboneBlockerPass.cs @@ -0,0 +1,72 @@ +/* + * MIT License + * + * Copyright (c) 2022 bd_ + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using System.Collections.Generic; +using UnityEngine; +using VRC.SDK3.Dynamics.PhysBone.Components; + +namespace nadena.dev.modular_avatar.core.editor +{ + internal class PhysboneBlockerPass + { + public static void Process(GameObject avatarRoot) + { + var blockers = avatarRoot.GetComponentsInChildren(true); + if (blockers.Length == 0) return; + + var physBones = avatarRoot.GetComponentsInChildren(true); + if (physBones.Length == 0) return; + + Dictionary> physBoneRootToIgnores = new Dictionary>(); + + var avatarTransform = avatarRoot.transform; + foreach (var tip in blockers) + { + var node = tip.transform; + // We deliberately skip the node itself to allow for a specific PhysBone to be attached here. + while (node != null && node != avatarTransform && node.parent != null) + { + node = node.parent; + if (!physBoneRootToIgnores.TryGetValue(node, out var parent)) + { + parent = new List(); + physBoneRootToIgnores.Add(node, parent); + } + + parent.Add(tip.transform); + node = node.parent; + } + } + + foreach (var pb in physBones) + { + var root = pb.rootTransform != null ? pb.rootTransform : pb.transform; + if (physBoneRootToIgnores.TryGetValue(root, out var ignores)) + { + pb.ignoreTransforms.AddRange(ignores); + } + } + } + } +} \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Editor/PhysboneBlockerPass.cs.meta b/Packages/nadena.dev.modular-avatar/Editor/PhysboneBlockerPass.cs.meta new file mode 100644 index 00000000..f9957f76 --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Editor/PhysboneBlockerPass.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 375dac2ebd964a6db0f271d0ab93da2f +timeCreated: 1669749518 \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Runtime/ModularAvatarPBBlocker.cs b/Packages/nadena.dev.modular-avatar/Runtime/ModularAvatarPBBlocker.cs new file mode 100644 index 00000000..964cc3d5 --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Runtime/ModularAvatarPBBlocker.cs @@ -0,0 +1,34 @@ +/* + * MIT License + * + * Copyright (c) 2022 bd_ + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +using UnityEngine; + +namespace nadena.dev.modular_avatar.core +{ + [DisallowMultipleComponent] + [AddComponentMenu("Modular Avatar/MA PhysBone Blocker")] + public class ModularAvatarPBBlocker : AvatarTagComponent + { + } +} \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Runtime/ModularAvatarPBBlocker.cs.meta b/Packages/nadena.dev.modular-avatar/Runtime/ModularAvatarPBBlocker.cs.meta new file mode 100644 index 00000000..a8671dd3 --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Runtime/ModularAvatarPBBlocker.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a5bf908a199a4648845ebe2fd3b5a4bd +timeCreated: 1669749485 \ No newline at end of file diff --git a/docs/docs/reference/physbone-blocker.md b/docs/docs/reference/physbone-blocker.md new file mode 100644 index 00000000..26e2afa7 --- /dev/null +++ b/docs/docs/reference/physbone-blocker.md @@ -0,0 +1,25 @@ +# PhysBone Blocker + +:::caution + +This component is planned to be added in 1.1.0, and is not available in the 1.0.x series. + +::: + +![PhysBone Blocker](physbone-blocker.png) + +The PhysBone Blocker prevents physbones rooted in parent objects from affecting a child object. +It does this by adding this child object to the Ignore list for any PhysBone affecting a parent object. + +## When should I use it? + +When making accessories that someone might want to attach to a PhysBone chain like a tail or an ear, +you can attach a PhysBone Blocker to prevent the parent PhysBone chain from affecting the child object. + +Note that you can still attach a PhysBone component to the child object that has the PhysBone Blocker on it. + +## Use with Bone Proxies + +When using the [Bone Proxy component](bone-proxy.md) to attach an object to a pre-existing PhysBone chain, +attaching the PhysBone blocker will ensure that your object is rigidly attached to the parent chain. +When doing this, it's best to have the PhysBone Blocker on the same object that has the Bone Proxy. \ No newline at end of file diff --git a/docs/docs/reference/physbone-blocker.png b/docs/docs/reference/physbone-blocker.png new file mode 100644 index 00000000..1d3c32d2 Binary files /dev/null and b/docs/docs/reference/physbone-blocker.png differ diff --git a/docs/i18n/ja/docusaurus-plugin-content-docs/current/reference/physbone-blocker.md b/docs/i18n/ja/docusaurus-plugin-content-docs/current/reference/physbone-blocker.md new file mode 100644 index 00000000..c3a0efe6 --- /dev/null +++ b/docs/i18n/ja/docusaurus-plugin-content-docs/current/reference/physbone-blocker.md @@ -0,0 +1,24 @@ +# PhysBone Blocker + +:::caution 注意 + +このコンポーネントは1.1.0で追加される予定であり、1.0.xでは利用できません。 + +::: + +![PhysBone Blocker](physbone-blocker.png) + +PhysBone Blockerは、子オブジェクトから親オブジェクトをルートとするPhysBoneの影響を防ぎます。 +親オブジェクトを影響するPhysBoneコンポーネントのIgnoreリストに子オブジェクトを追加することにより実装しています。 + +## いつ使うもの? + +PhysBoneによる揺れ物、例えば耳やしっぽにつけるアクセサリーを作るとき、PhysBone Blockerを付けることで +既存の親のPhysBoneの影響を防ぐことができます。 + +なお、PhysBone Blockerを付けた子オブジェクトでも、そのオブジェクトそのものにPhysBoneを付けることが可能です。 + +## Bone Proxiesとの使用 + +[Bone Proxy コンポーネント](bone-proxy.md)を使って、既存のPhysBoneチェーンに装着するとき、 +PhysBone Blockerも付けるとしっかりと親に固定できます。この時はPhysBone BlockerをBone Proxyと同じオブジェクトに付けることを推奨します。 \ No newline at end of file diff --git a/docs/i18n/ja/docusaurus-plugin-content-docs/current/reference/physbone-blocker.png b/docs/i18n/ja/docusaurus-plugin-content-docs/current/reference/physbone-blocker.png new file mode 100644 index 00000000..df6f6a20 Binary files /dev/null and b/docs/i18n/ja/docusaurus-plugin-content-docs/current/reference/physbone-blocker.png differ