mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2024-12-28 10:15:06 +08:00
feat: MA Convert Constraints (#1010)
This commit is contained in:
parent
d83c3351d7
commit
7384715059
8
.github/ProjectRoot/vpm-manifest-2022.json
vendored
8
.github/ProjectRoot/vpm-manifest-2022.json
vendored
@ -1,7 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.vrchat.avatars": {
|
||||
"version": "3.5.0"
|
||||
"version": "3.7.0"
|
||||
},
|
||||
"nadena.dev.ndmf": {
|
||||
"version": "1.4.0"
|
||||
@ -9,13 +9,13 @@
|
||||
},
|
||||
"locked": {
|
||||
"com.vrchat.avatars": {
|
||||
"version": "3.6.1",
|
||||
"version": "3.7.0",
|
||||
"dependencies": {
|
||||
"com.vrchat.base": "3.6.1"
|
||||
"com.vrchat.base": "3.7.0"
|
||||
}
|
||||
},
|
||||
"com.vrchat.base": {
|
||||
"version": "3.6.1",
|
||||
"version": "3.7.0",
|
||||
"dependencies": {}
|
||||
},
|
||||
"nadena.dev.ndmf": {
|
||||
|
14
Editor/Inspector/MAConvertConstraintsEditor.cs
Normal file
14
Editor/Inspector/MAConvertConstraintsEditor.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
[CustomEditor(typeof(ModularAvatarConvertConstraints))]
|
||||
[CanEditMultipleObjects]
|
||||
internal class MAConvertConstraintsEditor : MAEditorBase
|
||||
{
|
||||
protected override void OnInnerInspectorGUI()
|
||||
{
|
||||
// no UI
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/Inspector/MAConvertConstraintsEditor.cs.meta
Normal file
3
Editor/Inspector/MAConvertConstraintsEditor.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 484ea04548b945ce9cf5fd6d49b50244
|
||||
timeCreated: 1723778102
|
125
Editor/OptimizationPasses/ConstraintConverterPass.cs
Normal file
125
Editor/OptimizationPasses/ConstraintConverterPass.cs
Normal file
@ -0,0 +1,125 @@
|
||||
using System.Collections.Generic;
|
||||
using nadena.dev.ndmf;
|
||||
using UnityEditor;
|
||||
#if MA_VRCSDK3_AVATARS_3_7_0_OR_NEWER
|
||||
using UnityEngine;
|
||||
using UnityEngine.Animations;
|
||||
using VRC.SDK3.Avatars;
|
||||
using System.Linq;
|
||||
using nadena.dev.modular_avatar.animation;
|
||||
using VRC.Dynamics;
|
||||
#endif
|
||||
|
||||
namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
internal class ConstraintConverterPass : Pass<ConstraintConverterPass>
|
||||
{
|
||||
#if MA_VRCSDK3_AVATARS_3_7_0_OR_NEWER
|
||||
[InitializeOnLoadMethod]
|
||||
private static void Init()
|
||||
{
|
||||
AvatarDynamicsSetup.IsUnityConstraintAutoConverted += constraint =>
|
||||
{
|
||||
var component = constraint as Component;
|
||||
if (component == null) return false;
|
||||
|
||||
var converted = component.GetComponentInParent<ModularAvatarConvertConstraints>();
|
||||
|
||||
return converted != null && RuntimeUtil.FindAvatarInParents(converted.transform) ==
|
||||
RuntimeUtil.FindAvatarInParents(component.transform);
|
||||
};
|
||||
|
||||
AvatarDynamicsSetup.OnConvertUnityConstraintsAcrossGameObjects += (constraints, isAutoFix) =>
|
||||
{
|
||||
if (!isAutoFix) return false;
|
||||
|
||||
var avatars = constraints.Select(c => RuntimeUtil.FindAvatarInParents(c.transform)).Distinct();
|
||||
|
||||
foreach (var avatar in avatars) Undo.AddComponent<ModularAvatarConvertConstraints>(avatar.gameObject);
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Execute(ndmf.BuildContext context)
|
||||
{
|
||||
var converters = context.AvatarRootObject.GetComponentsInChildren<ModularAvatarConvertConstraints>(true)
|
||||
.Select(c => c.gameObject)
|
||||
.ToHashSet(new ObjectIdentityComparer<GameObject>());
|
||||
if (converters.Count == 0) return;
|
||||
|
||||
var constraintGameObjects = context.AvatarRootObject.GetComponentsInChildren<IConstraint>(true)
|
||||
.Select(c => (c as Component)?.gameObject)
|
||||
.Distinct()
|
||||
.Where(go => go.GetComponentsInParent<ModularAvatarConvertConstraints>(true)
|
||||
.Select(c => c.gameObject)
|
||||
.Any(converters.Contains)
|
||||
).ToArray();
|
||||
var targetConstraintComponents =
|
||||
constraintGameObjects.SelectMany(go => go.GetComponents<IConstraint>()).ToArray();
|
||||
|
||||
AvatarDynamicsSetup.DoConvertUnityConstraints(targetConstraintComponents, null, false);
|
||||
|
||||
var asc = context.Extension<AnimationServicesContext>();
|
||||
|
||||
// Also look for preexisting VRCConstraints so we can go fix up any broken animation clips from people who
|
||||
// clicked auto fix :(
|
||||
var existingVRCConstraints = converters.SelectMany(c => c.GetComponentsInChildren<VRCConstraintBase>(true))
|
||||
.Select(c => c.gameObject)
|
||||
.Distinct();
|
||||
|
||||
var targetPaths = constraintGameObjects
|
||||
.Union(existingVRCConstraints)
|
||||
.Select(c => asc.PathMappings.GetObjectIdentifier(c))
|
||||
.ToHashSet();
|
||||
|
||||
// Update animation clips
|
||||
var clips = targetPaths.SelectMany(tp => asc.AnimationDatabase.ClipsForPath(tp))
|
||||
.ToHashSet();
|
||||
|
||||
foreach (var clip in clips) RemapSingleClip(clip, targetPaths);
|
||||
}
|
||||
|
||||
private void RemapSingleClip(AnimationDatabase.ClipHolder clip, HashSet<string> targetPaths)
|
||||
{
|
||||
var motion = clip.CurrentClip as AnimationClip;
|
||||
if (motion == null) return;
|
||||
|
||||
var bindings = AnimationUtility.GetCurveBindings(motion);
|
||||
var toUpdateBindings = new List<EditorCurveBinding>();
|
||||
var toUpdateCurves = new List<AnimationCurve>();
|
||||
|
||||
foreach (var ecb in bindings)
|
||||
{
|
||||
if (!targetPaths.Contains(ecb.path)) continue;
|
||||
if (typeof(IConstraint).IsAssignableFrom(ecb.type))
|
||||
if (AvatarDynamicsSetup.TryGetSubstituteAnimationBinding(ecb.type, ecb.propertyName,
|
||||
out var newType, out var newProp, out var isArray))
|
||||
{
|
||||
var newBinding = new EditorCurveBinding
|
||||
{
|
||||
path = ecb.path,
|
||||
type = newType,
|
||||
propertyName = newProp
|
||||
};
|
||||
var curve = AnimationUtility.GetEditorCurve(motion, ecb);
|
||||
if (curve != null)
|
||||
{
|
||||
toUpdateBindings.Add(newBinding);
|
||||
toUpdateCurves.Add(curve);
|
||||
|
||||
toUpdateBindings.Add(ecb);
|
||||
toUpdateCurves.Add(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (toUpdateBindings.Count == 0) return;
|
||||
AnimationUtility.SetEditorCurves(motion, toUpdateBindings.ToArray(), toUpdateCurves.ToArray());
|
||||
}
|
||||
|
||||
#else
|
||||
protected override void Execute(ndmf.BuildContext context) {}
|
||||
#endif
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c172d4eac3d4902826a96656cf1ce34
|
||||
timeCreated: 1723776385
|
@ -70,6 +70,7 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
|
||||
seq.Run(BlendshapeSyncAnimationPluginPass.Instance);
|
||||
#endif
|
||||
seq.Run(GameObjectDelayDisablePass.Instance);
|
||||
seq.Run(ConstraintConverterPass.Instance);
|
||||
});
|
||||
#if MA_VRCSDK3_AVATARS
|
||||
seq.Run(MenuInstallPluginPass.Instance);
|
||||
|
@ -8,7 +8,8 @@
|
||||
"nadena.dev.ndmf",
|
||||
"nadena.dev.ndmf.vrchat",
|
||||
"nadena.dev.ndmf.reactive-query.core",
|
||||
"nadena.dev.ndmf.runtime"
|
||||
"nadena.dev.ndmf.runtime",
|
||||
"VRC.SDK3A.Editor"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
@ -19,7 +20,6 @@
|
||||
"precompiledReferences": [
|
||||
"Newtonsoft.Json.dll",
|
||||
"System.Collections.Immutable.dll",
|
||||
"System.Memory.dll",
|
||||
"VRCSDKBase.dll",
|
||||
"VRCSDKBase-Editor.dll",
|
||||
"VRCSDK3A.dll",
|
||||
@ -48,6 +48,11 @@
|
||||
"name": "com.vrchat.avatars",
|
||||
"expression": "3.5.2",
|
||||
"define": "MA_VRCSDK3_AVATARS_3_5_2_OR_NEWER"
|
||||
},
|
||||
{
|
||||
"name": "com.vrchat.avatars",
|
||||
"expression": "3.7.0-beta.2",
|
||||
"define": "MA_VRCSDK3_AVATARS_3_7_0_OR_NEWER"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
|
15
Runtime/ModularAvatarConvertConstraints.cs
Normal file
15
Runtime/ModularAvatarConvertConstraints.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
#if MA_VRCSDK3_AVATARS
|
||||
[AddComponentMenu("Modular Avatar/MA Convert Constraints")]
|
||||
#else
|
||||
[AddComponentMenu("")]
|
||||
#endif
|
||||
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/convert-constraints?lang=auto")]
|
||||
public class ModularAvatarConvertConstraints : AvatarTagComponent
|
||||
{
|
||||
}
|
||||
}
|
11
Runtime/ModularAvatarConvertConstraints.cs.meta
Normal file
11
Runtime/ModularAvatarConvertConstraints.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e362b3df8a3d478c82bf5ffe18f622e6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: a8edd5bd1a0a64a40aa99cc09fb5f198, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
17
docs~/docs/reference/convert-constraints.md
Normal file
17
docs~/docs/reference/convert-constraints.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Convert Constraints
|
||||
|
||||
The Convert Constraints component directs Modular Avatar to nondestructively convert Unity constraints to VRChat
|
||||
constraints on build. It will convert any constraints (and animations referencing them) on the same object it is
|
||||
attached to, and any children of that object. It will also attempt to fix animations broken by using VRCSDK's Auto Fix
|
||||
button with older versions of Modular Avatar.
|
||||
|
||||
## When should I use this?
|
||||
|
||||
It's probably a good idea to put this on your avatar root in most cases, as preconverting constraints improves
|
||||
performance significantly. When MA is installed, the VRChat Auto Fix button will automatically add this component to
|
||||
your avatar root if it's not already there.
|
||||
|
||||
## When should I not use this?
|
||||
|
||||
This component is primarily provided to allow users to disable this functionality (by removing this component) if it is
|
||||
suspected to be causing problems.
|
@ -0,0 +1,15 @@
|
||||
# Convert Constraints
|
||||
|
||||
Convert Constraintsコンポーネントは、ビルド時にUnityのConstraintsをVRChatのConstraintに非破壊的に変換するようにModular
|
||||
Avatarに指示します。
|
||||
アタッチされているオブジェクトとその子オブジェクトにあるConstraint、およびそれらを参照しているアニメーションを変換します。
|
||||
また、VRCSDKのAuto Fixを古いバージョンのModular Avatarで使用して壊れたアニメーションも修正しようとします。
|
||||
|
||||
## いつ使うもの?
|
||||
|
||||
あらかじめ変換するとパフォーマンスが大幅に向上するため、ほとんどの場合はアバタールートにこれを配置するのが良いでしょう。MAがインストールされている場合、
|
||||
VRChatのAuto Fixボタンは、アバタールートにこのコンポーネントがまだ存在しない場合、自動的にこのコンポーネントを追加します。
|
||||
|
||||
## 非推奨の場合
|
||||
|
||||
このコンポーネントは、問題の原因となる可能性がある場合に、このコンポーネントを削除してこの機能を無効にするために提供されています。
|
@ -15,7 +15,7 @@
|
||||
"com.unity.nuget.newtonsoft-json": "2.0.0"
|
||||
},
|
||||
"vpmDependencies": {
|
||||
"com.vrchat.avatars": ">=3.6.1",
|
||||
"com.vrchat.avatars": ">=3.7.0",
|
||||
"nadena.dev.ndmf": ">=1.5.0-beta.3 <2.0.0-a"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user