Disable foot IK on pose playables and add ball pose
- PlayerPoseController: add applyFootIK toggle (default off) and apply it to each pose playable so straight-knee idles render straight; Mecanim foot IK was bending the knees to plant the feet (162° instead of 180°). - Add Pose_Ball / Paintman-Ball animation and reorder the pose list. - Move StraightenKneesTool editor utility under Assets/Unused/Editor. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
5dd35dd0f9
commit
080b2a1c39
10 files changed
+11609
-82
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8de430ad75135743b87456111e7abac
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,21 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e3e6fee2893b9d848b8b1ccca743c14f, type: 3}
|
||||
m_Name: Pose_Ball
|
||||
m_EditorClassIdentifier: Assembly-CSharp::PlayerPose
|
||||
clip: {fileID: 7400000, guid: f8de430ad75135743b87456111e7abac, type: 2}
|
||||
clipSpeed: 1
|
||||
walkClip: {fileID: 0}
|
||||
walkClipSpeed: 1
|
||||
runClip: {fileID: 0}
|
||||
runClipSpeed: 1
|
||||
ceilingYOffset: 1
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c5cf9d420554e5e4e96d3bee1903967a
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -2213,12 +2213,14 @@ MonoBehaviour:
|
||||
poseSaveId:
|
||||
poses:
|
||||
- {fileID: 11400000, guid: 3b59c882f27d0d04a82d2db251af1728, type: 2}
|
||||
- {fileID: 11400000, guid: 1545cfba9b5e06d41ae72c7ec766baaf, type: 2}
|
||||
- {fileID: 11400000, guid: 649ecccdabb7ef9438addcec6663b037, type: 2}
|
||||
- {fileID: 11400000, guid: 1545cfba9b5e06d41ae72c7ec766baaf, type: 2}
|
||||
- {fileID: 11400000, guid: c5cf9d420554e5e4e96d3bee1903967a, type: 2}
|
||||
defaultPoseIndex: 0
|
||||
cycleKey: 17
|
||||
poseBlendDuration: 0.2
|
||||
ceilingOffsetSpeed: 4
|
||||
applyFootIK: 0
|
||||
--- !u!114 &1141039644
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -58,6 +58,11 @@ public partial class PlayerPoseController : MonoBehaviour
|
||||
[Min(0f)]
|
||||
[SerializeField] private float ceilingOffsetSpeed = 4f;
|
||||
|
||||
[Tooltip("Apply Mecanim foot IK to the played humanoid clips. Off (default) plays each pose exactly as " +
|
||||
"authored. On bends the knees to plant the feet on the IK goal, which makes a straight-knee idle " +
|
||||
"render visibly bent even when the clip's Lower Leg Stretch muscle is fully straight.")]
|
||||
[SerializeField] private bool applyFootIK = false;
|
||||
|
||||
private PlayerCharacterController _player;
|
||||
private Animator _animator;
|
||||
private string _graphName; // cached so building the graph allocates no string from the Update path
|
||||
@@ -269,6 +274,10 @@ public partial class PlayerPoseController : MonoBehaviour
|
||||
}
|
||||
|
||||
_toPlayable = AnimationClipPlayable.Create(_graph, clip);
|
||||
// Off by default: foot IK plants the foot on its goal and bends the knee to reach it, so a straight-knee
|
||||
// pose renders bent (SampleAnimation, which the authoring tools check against, never applies it). The
|
||||
// outgoing pose on input 0 is a former _toPlayable, so it already carries this setting.
|
||||
_toPlayable.SetApplyFootIK(applyFootIK);
|
||||
_mixer.ConnectInput(1, _toPlayable, 0);
|
||||
_toClip = clip;
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 963f2dea141da8d439f1433399db6d4e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,100 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Editor utility that pins the humanoid knee muscles to fully straight on selected animation clips.
|
||||
///
|
||||
/// On this project's auto-generated PaintmanAvatar, a fully straight leg corresponds to the
|
||||
/// "Lower Leg Stretch" muscle sitting at its maximum (1.0); anything below reads as a visibly bent
|
||||
/// knee (~8 deg per 0.1). Authoring tools (UMotion, Mixamo retargets) commonly land at ~0.93, which
|
||||
/// shows as the "slightly bent knees on an idle that should be straight" symptom. This tool sets the
|
||||
/// Left/Right Lower Leg Stretch curves to a constant 1.0 so the knees read as a true 180 deg.
|
||||
///
|
||||
/// Only native .anim humanoid clips can be edited — imported clips (FBX/Blend) are regenerated on
|
||||
/// import, so their curves can't be changed here and are skipped with a warning.
|
||||
/// </summary>
|
||||
public static class StraightenKneesTool
|
||||
{
|
||||
private const string LeftStretch = "Left Lower Leg Stretch";
|
||||
private const string RightStretch = "Right Lower Leg Stretch";
|
||||
private const float StraightValue = 1f; // muscle value that maps to a fully straight knee on this avatar
|
||||
|
||||
private const string ToolsMenu = "Tools/Chameleon/Straighten Knees (Selected Clips)";
|
||||
private const string AssetsMenu = "Assets/Chameleon/Straighten Knees";
|
||||
|
||||
[MenuItem(ToolsMenu, false, 100)]
|
||||
[MenuItem(AssetsMenu, false, 100)]
|
||||
private static void StraightenSelected()
|
||||
{
|
||||
List<AnimationClip> clips = GetSelectedClips();
|
||||
if (clips.Count == 0)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Straighten Knees",
|
||||
"Select one or more native (.anim) humanoid AnimationClips in the Project window.", "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
int changed = 0, skipped = 0;
|
||||
foreach (AnimationClip clip in clips)
|
||||
{
|
||||
if (StraightenClip(clip)) changed++;
|
||||
else skipped++;
|
||||
}
|
||||
|
||||
if (changed > 0)
|
||||
AssetDatabase.SaveAssets();
|
||||
|
||||
Debug.Log($"[Straighten Knees] Lower-leg stretch set to {StraightValue:0.##} on {changed} clip(s)" +
|
||||
(skipped > 0 ? $", skipped {skipped} (non-.anim or non-humanoid)." : "."));
|
||||
}
|
||||
|
||||
[MenuItem(ToolsMenu, true)]
|
||||
[MenuItem(AssetsMenu, true)]
|
||||
private static bool StraightenSelectedValidate() => GetSelectedClips().Count > 0;
|
||||
|
||||
private static bool StraightenClip(AnimationClip clip)
|
||||
{
|
||||
if (!clip)
|
||||
return false;
|
||||
|
||||
string path = AssetDatabase.GetAssetPath(clip);
|
||||
if (!path.EndsWith(".anim", System.StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Debug.LogWarning($"[Straighten Knees] '{clip.name}' is an imported clip ({path}); its curves are " +
|
||||
"regenerated on import and can't be edited. Make an editable .anim copy first.", clip);
|
||||
return false;
|
||||
}
|
||||
if (!clip.humanMotion)
|
||||
{
|
||||
Debug.LogWarning($"[Straighten Knees] '{clip.name}' is not a humanoid clip; skipped.", clip);
|
||||
return false;
|
||||
}
|
||||
|
||||
Undo.RegisterCompleteObjectUndo(clip, "Straighten Knees");
|
||||
SetMuscleConstant(clip, LeftStretch, StraightValue);
|
||||
SetMuscleConstant(clip, RightStretch, StraightValue);
|
||||
EditorUtility.SetDirty(clip);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Replaces (or adds) the named muscle curve with a flat constant across the whole clip.</summary>
|
||||
private static void SetMuscleConstant(AnimationClip clip, string muscle, float value)
|
||||
{
|
||||
var binding = EditorCurveBinding.FloatCurve(string.Empty, typeof(Animator), muscle);
|
||||
float end = clip.length > 0f ? clip.length : 1f / Mathf.Max(1f, clip.frameRate);
|
||||
var curve = new AnimationCurve(new Keyframe(0f, value), new Keyframe(end, value));
|
||||
AnimationUtility.SetEditorCurve(clip, binding, curve);
|
||||
}
|
||||
|
||||
private static List<AnimationClip> GetSelectedClips()
|
||||
{
|
||||
var result = new List<AnimationClip>();
|
||||
foreach (Object o in Selection.objects)
|
||||
{
|
||||
if (o is AnimationClip clip && !result.Contains(clip))
|
||||
result.Add(clip);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4fc3fefa8bfcb6a4abe9fdd8e395e6cf
|
||||
Reference in new issue
Block a user