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:
adminandClaude Opus 4.8 committed 2026-06-26 18:20:56 +02:00
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
+8
View File
@@ -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
+21
View File
@@ -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
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c5cf9d420554e5e4e96d3bee1903967a
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
+3 -1
View File
@@ -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
+9
View File
@@ -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;
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 963f2dea141da8d439f1433399db6d4e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+100
View File
@@ -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