Merge pull request #601 from ousttrue/feature/tpose_button

Feature/tpose button
This commit is contained in:
hiroj
2020-11-16 14:15:15 +09:00
committed by GitHub
6 changed files with 116 additions and 20 deletions

View File

@@ -25,6 +25,10 @@ namespace MeshUtility.Validators
[LangMsg(Languages.en, "The model needs to face the positive Z-axis")]
FACE_Z_POSITIVE_DIRECTION,
[LangMsg(Languages.ja, "T-Pose にしてください")]
[LangMsg(Languages.en, "Set T-Pose")]
NOT_TPOSE,
[LangMsg(Languages.ja, "ExportRootの Animator に Avatar がありません")]
[LangMsg(Languages.en, "No Avatar in ExportRoot's Animator")]
NO_AVATAR_IN_ANIMATOR,
@@ -37,7 +41,7 @@ namespace MeshUtility.Validators
[LangMsg(Languages.en, "Animator.avatar is not humanoid. Please change model's AnimationType to humanoid")]
AVATAR_IS_NOT_HUMANOID,
[LangMsg(Languages.ja, "humanoid設定に顎が含まれている。FBX importer の rig 設定に戻って設定を解除することをおすすめします")]
[LangMsg(Languages.ja, "Jaw(顎)ボーンが含まれています。意図していない場合は設定解除をおすすめします。FBX importer の rig 設定から変更できます")]
[LangMsg(Languages.en, "Jaw bone is included. It may not what you intended. Please check the humanoid avatar setting screen")]
JAW_BONE_IS_INCLUDED,
}
@@ -150,15 +154,23 @@ namespace MeshUtility.Validators
}
}
{
var lu = animator.GetBoneTransform(HumanBodyBones.LeftUpperArm);
var ll = animator.GetBoneTransform(HumanBodyBones.LeftLowerArm);
var ru = animator.GetBoneTransform(HumanBodyBones.RightUpperArm);
var rl = animator.GetBoneTransform(HumanBodyBones.RightLowerArm);
if (Vector3.Dot((ll.position - lu.position).normalized, Vector3.left) < 0.8f
|| Vector3.Dot((rl.position - ru.position).normalized, Vector3.right) < 0.8f)
{
yield return Validation.Error(ValidationMessages.NOT_TPOSE.Msg());
}
}
var jaw = animator.GetBoneTransform(HumanBodyBones.Jaw);
if (jaw != null)
{
yield return Validation.Warning(ValidationMessages.JAW_BONE_IS_INCLUDED.Msg());
}
else
{
yield return Validation.Info("Animator OK");
}
}
}
}

View File

@@ -48,5 +48,7 @@ namespace VRM
UseSparseAccessorForMorphTarget = UseSparseAccessor,
ExportOnlyBlendShapePosition = OnlyBlendshapePosition,
};
public GameObject Root { get; set; }
}
}

View File

@@ -36,12 +36,6 @@ namespace VRM
}
}
/// <summary>
/// エクスポート時に強制的にT-Pose化する
/// </summary>
[Tooltip("Option")]
public bool ForceTPose = false;
/// <summary>
/// エクスポート時にヒエラルキーの正規化を実施する
/// </summary>
@@ -78,7 +72,6 @@ namespace VRM
[Tooltip("Remove blendShapeClip that preset is Unknown")]
public bool ReduceBlendshapeClip = false;
CheckBoxProp m_forceTPose;
CheckBoxProp m_poseFreeze;
CheckBoxProp m_useSparseAccessor;
CheckBoxProp m_onlyBlendShapePosition;
@@ -123,11 +116,22 @@ namespace VRM
[LangMsg(Languages.ja, "エクスポートに頂点カラーを含めない")]
[LangMsg(Languages.en, "Vertex color will not be exported")]
REMOVE_VERTEX_COLOR,
[LangMsg(Languages.ja, "このボタンで自動で T-Pose にできます。手動で T-Pose にしたり、ボタンの後で手直ししてもOKです。")]
[LangMsg(Languages.en, "You can automatically set the T pose with this button. You can change it manually to T-pose or after the button.")]
ENALBE_TPOSE_BUTTON,
[LangMsg(Languages.ja, "このボタンで自動で T-Pose にできます。prefab には実行できません。")]
[LangMsg(Languages.en, "You can set the T pose automatically with this button. It cannot be run on prefabs.")]
DISABLE_TPOSE_BUTTON,
[LangMsg(Languages.ja, "T-Pose にする")]
[LangMsg(Languages.en, "Make T-Pose")]
DO_TPOSE,
}
private void OnEnable()
{
m_forceTPose = new CheckBoxProp(serializedObject.FindProperty(nameof(ForceTPose)), Options.FORCE_T_POSE);
m_poseFreeze = new CheckBoxProp(serializedObject.FindProperty(nameof(PoseFreeze)), Options.NORMALIZE);
m_useSparseAccessor = new CheckBoxProp(serializedObject.FindProperty(nameof(UseSparseAccessor)), Options.BLENDSHAPE_USE_SPARSE);
m_onlyBlendShapePosition = new CheckBoxProp(serializedObject.FindProperty(nameof(OnlyBlendshapePosition)), Options.BLENDSHAPE_EXCLUDE_NORMAL_AND_TANGENT);
@@ -137,9 +141,33 @@ namespace VRM
public override void OnInspectorGUI()
{
GUILayout.Space(20);
var settings = (VRMExportSettings)target;
var root = settings.Root;
var backup = GUI.enabled;
GUI.enabled = root.scene.IsValid();
if (GUI.enabled)
{
EditorGUILayout.HelpBox(Options.ENALBE_TPOSE_BUTTON.Msg(), MessageType.Info);
}
else
{
EditorGUILayout.HelpBox(Options.DISABLE_TPOSE_BUTTON.Msg(), MessageType.Warning);
}
if (GUILayout.Button(Options.DO_TPOSE.Msg()))
{
if (settings.Root)
{
VRMBoneNormalizer.EnforceTPose(settings.Root);
}
}
GUI.enabled = backup;
GUILayout.Space(20);
// ToDo: 任意の BlendShapeClip を適用する
EditorGUIUtility.labelWidth = 160;
serializedObject.Update();
m_forceTPose.Draw();
m_poseFreeze.Draw();
m_useSparseAccessor.Draw();
m_onlyBlendShapePosition.Draw();

View File

@@ -23,6 +23,7 @@ namespace VRM
{
Meta,
Mesh,
BlendShape,
ExportSettings,
}
Tabs _tab;
@@ -301,18 +302,71 @@ namespace VRM
m_metaEditor.OnInspectorGUI();
break;
case Tabs.ExportSettings:
m_settingsInspector.OnInspectorGUI();
break;
case Tabs.Mesh:
m_meshesInspector.OnInspectorGUI();
break;
case Tabs.BlendShape:
if (m_state.ExportRoot)
{
OnBlendShapeGUI(m_state.ExportRoot.GetComponent<VRMBlendShapeProxy>());
}
break;
case Tabs.ExportSettings:
m_settings.Root = m_state.ExportRoot;
m_settingsInspector.OnInspectorGUI();
break;
}
return true;
}
BlendShapeMerger m_merger;
int m_selected = 0;
void OnBlendShapeGUI(VRMBlendShapeProxy proxy)
{
if (!m_state.ExportRoot.scene.IsValid())
{
EditorGUILayout.HelpBox("prefab は操作できません", MessageType.Warning);
return;
}
if (!proxy)
{
return;
}
var avatar = proxy.BlendShapeAvatar;
if (!avatar)
{
return;
}
m_merger = new BlendShapeMerger(avatar.Clips, proxy.transform);
GUILayout.Space(20);
EditorGUILayout.HelpBox("シーン上のExportRootにBlendShapeを適用します。Exportすると適用された状態がBakeされます。", MessageType.Info);
var options = avatar.Clips.Select(x => x.ToString()).ToArray();
m_selected = EditorGUILayout.Popup("select blendshape", m_selected, options);
if (GUILayout.Button("選択されたBlendShapeを適用する"))
{
m_merger.SetValues(avatar.Clips.Select((x, i) => new KeyValuePair<BlendShapeKey, float>(x.Key, i == m_selected ? 1 : 0)));
m_merger.Apply();
m_settings.PoseFreeze = true;
}
if (GUILayout.Button("BlendShapeをClearする"))
{
m_merger.SetValues(avatar.Clips.Select(x => new KeyValuePair<BlendShapeKey, float>(x.Key, 0)));
m_merger.Apply();
}
}
const string EXTENSION = ".vrm";
private static string m_lastExportDir;
static void OnExportClicked(GameObject root, VRMMetaObject meta, VRMExportSettings settings, VRMExportMeshes meshes)

View File

@@ -11,7 +11,7 @@ namespace VRM
/// <summary>
/// ブレンドシェイプを蓄えてまとめて適用するクラス
/// </summary>
class BlendShapeMerger
public class BlendShapeMerger
{
/// <summary>
/// Key からBlendShapeClipを得る

View File

@@ -9,7 +9,7 @@ namespace VRM
{
public static class VRMBoneNormalizer
{
static void EnforceTPose(GameObject go)
public static void EnforceTPose(GameObject go)
{
var animator = go.GetComponent<Animator>();
if (animator == null)