Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/tpose button #601

Merged
merged 6 commits into from Nov 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -25,6 +25,10 @@ public enum ValidationMessages
[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,
Expand All @@ -37,7 +41,7 @@ public enum ValidationMessages
[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,
}
Expand Down Expand Up @@ -150,15 +154,23 @@ public static IEnumerable<Validation> Validate(GameObject ExportRoot)
}
}

{
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");
}
}
}
}
2 changes: 2 additions & 0 deletions Assets/VRM/UniVRM/Editor/Format/VRMExportSettings.cs
Expand Up @@ -48,5 +48,7 @@ public class VRMExportSettings : ScriptableObject
UseSparseAccessorForMorphTarget = UseSparseAccessor,
ExportOnlyBlendShapePosition = OnlyBlendshapePosition,
};

public GameObject Root { get; set; }
}
}
46 changes: 37 additions & 9 deletions Assets/VRM/UniVRM/Editor/Format/VRMExportSettingsEditor.cs
Expand Up @@ -36,12 +36,6 @@ public void Draw()
}
}

/// <summary>
/// エクスポート時に強制的にT-Pose化する
/// </summary>
[Tooltip("Option")]
public bool ForceTPose = false;

/// <summary>
/// エクスポート時にヒエラルキーの正規化を実施する
/// </summary>
Expand Down Expand Up @@ -78,7 +72,6 @@ public void Draw()
[Tooltip("Remove blendShapeClip that preset is Unknown")]
public bool ReduceBlendshapeClip = false;

CheckBoxProp m_forceTPose;
CheckBoxProp m_poseFreeze;
CheckBoxProp m_useSparseAccessor;
CheckBoxProp m_onlyBlendShapePosition;
Expand Down Expand Up @@ -123,11 +116,22 @@ enum Options
[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);
Expand All @@ -137,9 +141,33 @@ private void OnEnable()

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();
Expand Down
62 changes: 58 additions & 4 deletions Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs
Expand Up @@ -23,6 +23,7 @@ enum Tabs
{
Meta,
Mesh,
BlendShape,
ExportSettings,
}
Tabs _tab;
Expand Down Expand Up @@ -301,18 +302,71 @@ bool DrawWizardGUI()
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)
Expand Down
2 changes: 1 addition & 1 deletion Assets/VRM/UniVRM/Scripts/BlendShape/BlendShapeMerger.cs
Expand Up @@ -11,7 +11,7 @@ namespace VRM
/// <summary>
/// ブレンドシェイプを蓄えてまとめて適用するクラス
/// </summary>
class BlendShapeMerger
public class BlendShapeMerger
{
/// <summary>
/// Key からBlendShapeClipを得る
Expand Down
Expand Up @@ -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)
Expand Down