Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Reset to T pose

Discussion in 'Animation' started by local306, Apr 15, 2016.

  1. local306

    local306

    Joined:
    Feb 28, 2016
    Posts:
    155
    While I was in the editor, I was sliding through some animation frames for my character. I've noticed that after doing so, my character remains in whatever pose they were in last when I start my game. This kind of breaks certain things like how my camera is setup and such.

    Untitled-1.png

    Is there a way to clear the current pose and return to the default T pose?
     
  2. Viniterra

    Viniterra

    Joined:
    Dec 4, 2014
    Posts:
    193
    Hi, I had discovered a way:

    Look for your default model in assets, and expand it. There must be a default T-pose animation. Drag it to the Animator Controller as a new state. Then open the Animations window, select the T-pose state, and then select a frame on it. You will see that the character returns to default T-pose. You can close the animation window and delete the T-pose state you had dragged into the Animator Controller.
     
  3. JotaRata

    JotaRata

    Joined:
    Dec 8, 2014
    Posts:
    61
    This is an old thread but if anyone is lost with this, I suggest to select all of your model bones, and reset their transforms to prefab, I think this may occur when you save while you are previewing an animation.
     
    NotLLamaLord and calpolican like this.
  4. protopop

    protopop

    Joined:
    May 19, 2009
    Posts:
    1,562
    Thank you! Ive been trying to figure this out for months.

    Your method worked perfectly.

    I didn't have a t-pose so i downloaded a free one from Mixamo, changed its rig to Humanoid, and used that.
     
    spikezart and Viniterra like this.
  5. Ng0ns

    Ng0ns

    Joined:
    Jun 21, 2016
    Posts:
    197
    For people using blender.
    If your fbx contains multiple animation clips (actions) and you wish to have a certain as default (first frame), go to the action editor and hit stash on the clip you want .You should be able to see it in the "Nonlinear animation" window, while there remember to hit the star icon on the action. Now the start frame should be the default when importing into Unity.
     
    Atto2O likes this.
  6. Blindleistung

    Blindleistung

    Joined:
    Apr 16, 2018
    Posts:
    2
    It looks like this no longer works in Unity 2020.1 . With the animation window open, the character adjusts as expected, but as soon as the window is closed, the character resets to the way it was before. I cannot find some 'apply' button.
     
    chadfranklin47 likes this.
  7. isbeorn

    isbeorn

    Joined:
    Nov 11, 2013
    Posts:
    2
    I too am having problems with this.

    @Ng0ns
    I'm using Blender and I know enough to know that I don't know enough about Blender. I have done as you suggested, pushing the action I want as default to an NLA strip and marking it with the star before exporting. But it doesn't work. A different action becomes the first one in Unity. I am exporting to FBX but without "NLA strips" selected, only "All actions", because it seems I can't get them to import otherwise in Unity. Are there more things I should be aware about in export/import? Unity 2019.3 and Blender 2.82.
     
  8. sacb0y

    sacb0y

    Joined:
    May 9, 2016
    Posts:
    936
    I also have this problem where my characters default pose is changed, but you can't select all the bones at once and reset their position :/
     
  9. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I just ran into this myself. Here's something that may help: it lets you copy a pose and apply it to another character, provided they have the same bone structure.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using System.Text;
    4. using UnityEngine;
    5. using UnityEditor;
    6.  
    7. public class CopyPastePose : MonoBehaviour
    8. {
    9.     [System.Serializable]
    10.     public class TransformInfo {
    11.         public string name;
    12.         public Vector3 rotation;
    13.         public TransformInfo[] children;
    14.        
    15.         public void BuildString(StringBuilder sb) {
    16.             sb.Append(string.Format("{0}|{1},{2},{3}", name, rotation.x, rotation.y, rotation.z));
    17.             if (children != null && children.Length > 0) {
    18.                 sb.Append("\n(\n");
    19.                 for (int i=0; i<children.Length; i++) children[i].BuildString(sb);
    20.                 sb.Append(")");
    21.             }
    22.             sb.Append("\n");
    23.         }
    24.        
    25.         public static TransformInfo FromString(string[] lines, ref int idx) {
    26.             string s = lines[idx];
    27.             int delim = s.IndexOf('|');
    28.             var result = new TransformInfo();
    29.             result.name = s.Substring(0, delim);
    30.             string[] fields = s.Substring(delim+1).Split(new char[]{','});
    31.             float.TryParse(fields[0], out result.rotation.x);
    32.             float.TryParse(fields[1], out result.rotation.y);
    33.             float.TryParse(fields[2], out result.rotation.z);
    34.             idx++;
    35.             if (idx >= lines.Length || lines[idx] != "(") {
    36.                 return result;
    37.             }
    38.             var chilluns = new List<TransformInfo>();
    39.             idx++;
    40.             while (idx < lines.Length && lines[idx] != ")") {
    41.                 chilluns.Add(FromString(lines, ref idx));
    42.             }
    43.             idx++;
    44.             result.children = chilluns.ToArray();
    45.             return result;
    46.            
    47.         }
    48.     }
    49.    
    50.     [MenuItem("Window/Animation/Copy Pose")]
    51.     static void CopyPose() {
    52.         Transform obj = Selection.activeTransform;
    53.         var info = GetInfo(obj);
    54.         var sb  = new StringBuilder();
    55.         info.BuildString(sb);
    56.         GUIUtility.systemCopyBuffer = sb.ToString();
    57.         Debug.Log("Copied pose of " + obj.name);
    58.     }
    59.    
    60.     [MenuItem("Window/Animation/Copy Pose", true)]
    61.     static bool ValidateCopyPose() {
    62.         return Selection.activeTransform != null;
    63.     }
    64.    
    65.     [MenuItem("Window/Animation/Paste Pose")]
    66.     static void PastePose() {
    67.         Transform obj = Selection.activeTransform;
    68.         var data = GUIUtility.systemCopyBuffer;
    69.         int idx = 0;
    70.         var info = TransformInfo.FromString(data.Split(new char[]{'\n'}), ref idx);
    71.         ApplyInfo(obj, info);
    72.         Debug.Log("Pasted pose onto " + obj.name);
    73.     }
    74.    
    75.     [MenuItem("Window/Animation/Paste Pose", true)]
    76.     static bool ValidatePastePose() {
    77.         return Selection.activeTransform != null && !string.IsNullOrEmpty(GUIUtility.systemCopyBuffer);
    78.     }
    79.  
    80.  
    81.     static TransformInfo GetInfo(Transform t) {
    82.         var result = new TransformInfo();
    83.         result.name = t.name;
    84.         result.rotation = t.localRotation.eulerAngles;
    85.         if (t.childCount > 0) {
    86.             result.children = new TransformInfo[t.childCount];
    87.             for (int i=0; i<t.childCount; i++) result.children[i] = GetInfo(t.GetChild(i));
    88.         }
    89.         return result;
    90.     }
    91.    
    92.     static void ApplyInfo(Transform t, TransformInfo info) {
    93.         t.localRotation = Quaternion.Euler(info.rotation);
    94.         if (info.children == null) return;
    95.         foreach (var childInfo in info.children) {
    96.             var tchild = t.Find(childInfo.name);
    97.             if (tchild != null) ApplyInfo(tchild, childInfo);
    98.             else Debug.Log("Couldn't find child " + childInfo.name + " of " + t.name, t.gameObject);
    99.         }
    100.     }
    101. }
    Just put this anywhere in your project, and then you'll find new Window > Animation > Copy Pose and Paste Pose menu commands.

    In my case this helped because I had an original avatar that was in a proper T-pose, but after generating a character with a character editor, it was in a silly hand-on-hip leaning-to-one-side pose. So with this I could copy the T-pose from the original and apply it to the custom character.

    Note that this script was a lot simpler & shorter before I discovered that Unity's JsonUtility sucks. But I hope somebody finds it useful anyway.
     
  10. azaridi

    azaridi

    Joined:
    Aug 17, 2015
    Posts:
    3
    Exporting from Blender (drag and drop to unity editor),
    Expand the blend file in the unity editor ,
    Find the 'Scene (Read-only)' object and double click it (marked with a little triangle) - the animation tab should open.
    Create a new animation , say idle.anim and copy the values of the 0 frame from 'Scene'
    Play the new clip to reset pose to whatever it was to start with - i assume a T-pose
     
  11. Akshay_ROG

    Akshay_ROG

    Joined:
    Sep 13, 2013
    Posts:
    48
    This works in any version. In better words: You must create a T pose animation, create a animation clip when importing, then in animator controller add that animation clip as a state. Then with the gameObject selected in the scene, select the state in the animator controller, the animation window (Ctrl+6) will show the animation as read only, select any frame or go to the end of the timeline (if the animation has only 1 frame) and your gameObject will set itself to the T pose.
     
  12. Onsterion

    Onsterion

    Joined:
    Feb 21, 2014
    Posts:
    215
    This doesn't work in Unity 2020.1. The poses in editor are bugged
     
  13. mehdihasheminia

    mehdihasheminia

    Joined:
    Sep 24, 2018
    Posts:
    1
    Using 'Animation window trick' to restore T-pose doesn't usually work on newer Unity versions (2020,2019,etc...), maybe because there is now another source of pose alteration: Timeline.
    I have recently solved my T-Pose problem using Timeline on Unity 2019.4.0f1 as below:

    1- Set up an empty Timeline
    • Create an empty object
    • Open Windows > Sequencing > Timeline
    • Click on 'create' button. As it's going to create a playable asset, it asks for a name. Enter any name and then 'save'. (you can also use other methods to create an empty timeline)
    • Now a 'playable director' is added to your game object.(ignore the animator).
    • Do not add new tracks to Timeline for now.
    2- Add T-Pose animation to the character animator as 'default state'
    • Prepare a T-Pose animation clip. ( you can download it from Mixamo & Import as Humanoid)
    • Select the animated character you want to restore T-Pose on. Drop downloaded T-Pose animation onto a full-body layer(like Base) of the 'Animator' of the character.
    • This is important: Right click on T-Pose clip and 'Set as layer Default State' temporarily.
    • you can delete this clip and reset default state after T-Pose is restored .
    3- Add character Animation track to the Timeline
    • Drag your character game-object from scene hierarchy onto timeline window we created at step 1.
    • Choose 'Add Animation Track'.
    • After creating an animation track, even without adding any animations, Timeline restore 'default state' pose of the animator for the character, which is T-pose in our case.
    • Now you can delete time-line object too.
    I hope it works for you as well. Keep me updated!

    PS: This is certainly a bug we wish unity could get rid of.
     
    MisterAndersun likes this.
  14. I-N-F

    I-N-F

    Joined:
    Apr 25, 2018
    Posts:
    1
    thanks a lot for this code man, this can be really be useful besides being a solution to problems like this, i tried the following methods they said but i didn't work out to me. i use 2019.4.11 by the way tho
     
    JoeStrout likes this.
  15. azevedco

    azevedco

    Joined:
    Mar 2, 2014
    Posts:
    34
    Updated the above script to include bone positions for copy and paste.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using System.Text;
    4. using UnityEngine;
    5. using UnityEditor;
    6.  
    7. public class CopyPastePose : MonoBehaviour
    8.     {
    9.         [System.Serializable]
    10.         public class TransformInfo
    11.         {
    12.             public string name;
    13.             public Vector3 rotation;
    14.             public Vector3 position;
    15.             public TransformInfo[] children;
    16.  
    17.             public void BuildString(StringBuilder sb)
    18.             {
    19.                 sb.Append(string.Format("{0}|{1},{2},{3},{4},{5},{6}", name, rotation.x, rotation.y, rotation.z, position.x, position.y, position.z));
    20.                 if (children != null && children.Length > 0)
    21.                 {
    22.                     sb.Append("\n(\n");
    23.                     for (int i = 0; i < children.Length; i++) children[i].BuildString(sb);
    24.                     sb.Append(")");
    25.                 }
    26.                 sb.Append("\n");
    27.             }
    28.  
    29.             public static TransformInfo FromString(string[] lines, ref int idx)
    30.             {
    31.                 string s = lines[idx];
    32.                 int delim = s.IndexOf('|');
    33.                 var result = new TransformInfo();
    34.                 result.name = s.Substring(0, delim);
    35.                 string[] fields = s.Substring(delim + 1).Split(new char[] { ',' });
    36.                 float.TryParse(fields[0], out result.rotation.x);
    37.                 float.TryParse(fields[1], out result.rotation.y);
    38.                 float.TryParse(fields[2], out result.rotation.z);
    39.                 float.TryParse(fields[3], out result.position.x);
    40.                 float.TryParse(fields[4], out result.position.y);
    41.                 float.TryParse(fields[5], out result.position.z);
    42.                 idx++;
    43.                 if (idx >= lines.Length || lines[idx] != "(")
    44.                 {
    45.                     return result;
    46.                 }
    47.                 var chilluns = new List<TransformInfo>();
    48.                 idx++;
    49.                 while (idx < lines.Length && lines[idx] != ")")
    50.                 {
    51.                     chilluns.Add(FromString(lines, ref idx));
    52.                 }
    53.                 idx++;
    54.                 result.children = chilluns.ToArray();
    55.                 return result;
    56.  
    57.             }
    58.         }
    59.  
    60.         [MenuItem("Tools/Copy Paste Pose/Copy Pose")]
    61.         static void CopyPose()
    62.         {
    63.             Transform obj = Selection.activeTransform;
    64.             var info = GetInfo(obj);
    65.             var sb = new StringBuilder();
    66.             info.BuildString(sb);
    67.             GUIUtility.systemCopyBuffer = sb.ToString();
    68.             Debug.Log("Copied pose of " + obj.name);
    69.         }
    70.  
    71.         [MenuItem("Tools/Copy Paste Pose/Copy Pose", true)]
    72.         static bool ValidateCopyPose()
    73.         {
    74.             return Selection.activeTransform != null;
    75.         }
    76.  
    77.         [MenuItem("Tools/Copy Paste Pose/Paste Pose")]
    78.         static void PastePose()
    79.         {
    80.             Transform obj = Selection.activeTransform;
    81.             var data = GUIUtility.systemCopyBuffer;
    82.             int idx = 0;
    83.             var info = TransformInfo.FromString(data.Split(new char[] { '\n' }), ref idx);
    84.             ApplyInfo(obj, info);
    85.             Debug.Log("Pasted pose onto " + obj.name);
    86.         }
    87.  
    88.         [MenuItem("Tools/Copy Paste Pose/Paste Pose", true)]
    89.         static bool ValidatePastePose()
    90.         {
    91.             return Selection.activeTransform != null && !string.IsNullOrEmpty(GUIUtility.systemCopyBuffer);
    92.         }
    93.  
    94.  
    95.         static TransformInfo GetInfo(Transform t)
    96.         {
    97.             var result = new TransformInfo();
    98.             result.name = t.name;
    99.             result.rotation = t.localRotation.eulerAngles;
    100.             result.position = t.localPosition;
    101.             if (t.childCount > 0)
    102.             {
    103.                 result.children = new TransformInfo[t.childCount];
    104.                 for (int i = 0; i < t.childCount; i++) result.children[i] = GetInfo(t.GetChild(i));
    105.             }
    106.             return result;
    107.         }
    108.  
    109.         static void ApplyInfo(Transform t, TransformInfo info)
    110.         {
    111.             t.localRotation = Quaternion.Euler(info.rotation);
    112.             t.localPosition = info.position;
    113.             if (info.children == null) return;
    114.             foreach (var childInfo in info.children)
    115.             {
    116.                 var tchild = t.Find(childInfo.name);
    117.                 if (tchild != null) ApplyInfo(tchild, childInfo);
    118.                 else Debug.Log("Couldn't find child " + childInfo.name + " of " + t.name, t.gameObject);
    119.             }
    120.         }
    121.     }
     
    jeromeWork and I-N-F like this.
  16. darketernal666666

    darketernal666666

    Joined:
    Dec 22, 2020
    Posts:
    11
    Out of curiosity why does this motorcycle pose for an avatar happen to begin with? I don't see any advantage in having the avatar doing this position , what where the people at unity thinking?
     
  17. igrir

    igrir

    Joined:
    Jan 24, 2014
    Posts:
    16
    I added a little bit addition by also setting the scale of target objects
    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Text;
    5. using UnityEngine;
    6. using UnityEditor;
    7.  
    8. public class CopyPastePose : MonoBehaviour
    9. {
    10.         [System.Serializable]
    11.         public class TransformInfo
    12.         {
    13.             public string name;
    14.             public Vector3 rotation;
    15.             public Vector3 position;
    16.             public Vector3 scale;
    17.             public TransformInfo[] children;
    18.  
    19.             public void BuildString(StringBuilder sb)
    20.             {
    21.                 sb.Append(string.Format("{0}|{1},{2},{3},{4},{5},{6},{7},{8},{9}", name, rotation.x, rotation.y, rotation.z, position.x, position.y, position.z, scale.x, scale.y, scale.z));
    22.                 if (children != null && children.Length > 0)
    23.                 {
    24.                     sb.Append("\n(\n");
    25.                     for (int i = 0; i < children.Length; i++) children[i].BuildString(sb);
    26.                     sb.Append(")");
    27.                 }
    28.                 sb.Append("\n");
    29.             }
    30.  
    31.             public static TransformInfo FromString(string[] lines, ref int idx)
    32.             {
    33.                 string s = lines[idx];
    34.                 int delim = s.IndexOf('|');
    35.                 var result = new TransformInfo();
    36.                 result.name = s.Substring(0, delim);
    37.                 string[] fields = s.Substring(delim + 1).Split(new char[] { ',' });
    38.                 float.TryParse(fields[0], out result.rotation.x);
    39.                 float.TryParse(fields[1], out result.rotation.y);
    40.                 float.TryParse(fields[2], out result.rotation.z);
    41.                 float.TryParse(fields[3], out result.position.x);
    42.                 float.TryParse(fields[4], out result.position.y);
    43.                 float.TryParse(fields[5], out result.position.z);
    44.                 float.TryParse(fields[6], out result.scale.x);
    45.                 float.TryParse(fields[7], out result.scale.y);
    46.                 float.TryParse(fields[8], out result.scale.z);
    47.                 idx++;
    48.                 if (idx >= lines.Length || lines[idx] != "(")
    49.                 {
    50.                     return result;
    51.                 }
    52.                 var chilluns = new List<TransformInfo>();
    53.                 idx++;
    54.                 while (idx < lines.Length && lines[idx] != ")")
    55.                 {
    56.                     chilluns.Add(FromString(lines, ref idx));
    57.                 }
    58.                 idx++;
    59.                 result.children = chilluns.ToArray();
    60.                 return result;
    61.  
    62.             }
    63.         }
    64.  
    65.         [MenuItem("Tools/Copy Paste Pose/Copy Pose")]
    66.         static void CopyPose()
    67.         {
    68.             Transform obj = Selection.activeTransform;
    69.             var info = GetInfo(obj);
    70.             var sb = new StringBuilder();
    71.             info.BuildString(sb);
    72.             GUIUtility.systemCopyBuffer = sb.ToString();
    73.             Debug.Log("Copied pose of " + obj.name);
    74.         }
    75.  
    76.         [MenuItem("Tools/Copy Paste Pose/Copy Pose", true)]
    77.         static bool ValidateCopyPose()
    78.         {
    79.             return Selection.activeTransform != null;
    80.         }
    81.  
    82.         [MenuItem("Tools/Copy Paste Pose/Paste Pose")]
    83.         static void PastePose()
    84.         {
    85.             Transform obj = Selection.activeTransform;
    86.             var data = GUIUtility.systemCopyBuffer;
    87.             int idx = 0;
    88.             var info = TransformInfo.FromString(data.Split(new char[] { '\n' }), ref idx);
    89.             ApplyInfo(obj, info);
    90.             Debug.Log("Pasted pose onto " + obj.name);
    91.         }
    92.  
    93.         [MenuItem("Tools/Copy Paste Pose/Paste Pose", true)]
    94.         static bool ValidatePastePose()
    95.         {
    96.             return Selection.activeTransform != null && !string.IsNullOrEmpty(GUIUtility.systemCopyBuffer);
    97.         }
    98.  
    99.  
    100.         static TransformInfo GetInfo(Transform t)
    101.         {
    102.             var result = new TransformInfo();
    103.             result.name = t.name;
    104.             result.rotation = t.localRotation.eulerAngles;
    105.             result.position = t.localPosition;
    106.             result.scale = t.localScale;
    107.             if (t.childCount > 0)
    108.             {
    109.                 result.children = new TransformInfo[t.childCount];
    110.                 for (int i = 0; i < t.childCount; i++) result.children[i] = GetInfo(t.GetChild(i));
    111.             }
    112.             return result;
    113.         }
    114.  
    115.         static void ApplyInfo(Transform t, TransformInfo info)
    116.         {
    117.             t.localRotation = Quaternion.Euler(info.rotation);
    118.             t.localPosition = info.position;
    119.             t.localScale = info.scale;
    120.             if (info.children == null) return;
    121.             foreach (var childInfo in info.children)
    122.             {
    123.                 var tchild = t.Find(childInfo.name);
    124.                 if (tchild != null) ApplyInfo(tchild, childInfo);
    125.                 else Debug.Log("Couldn't find child " + childInfo.name + " of " + t.name, t.gameObject);
    126.             }
    127.         }
    128.     }
    129.  
     
    jeromeWork, JoeStrout and I-N-F like this.
  18. JohnTomorrow

    JohnTomorrow

    Joined:
    Apr 19, 2013
    Posts:
    135
    Just ran into this, if you want to create a tpose animation from your original model you can use this script I threw together:

    Code (CSharp):
    1.  
    2. public void CreateTPose() {
    3.     var recorder = new GameObjectRecorder(animator.gameObject);
    4.     recorder.BindComponentsOfType<Transform>(animator.gameObject, true);
    5.     recorder.TakeSnapshot(0f);
    6.     var tempClip = new AnimationClip();
    7.     CurveFilterOptions filterOptions = new CurveFilterOptions();
    8.     recorder.SaveToClip(tempClip, 30, filterOptions);
    9.     AssetDatabase.CreateAsset(tempClip, EditorUtility.SaveFilePanel("Save", Application.dataPath, "test", "anim").Replace(Application.dataPath, "Assets"));
    10. }
    11.  
     
    Last edited: Aug 15, 2021
  19. makaolachsiungca

    makaolachsiungca

    Joined:
    Sep 27, 2019
    Posts:
    31
    here is the script for humanoid character,
    it require vaild Animator and avatar.

    ** put the script at Editor folder and select the character root(Animator) in scene then look up to Tools/Character/Force T-Pose**


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5. using System.Linq;
    6. public class ForceTPose
    7. {
    8.     [MenuItem("Tools/Character/ForceT-Pose")]
    9.     static void TPose()
    10.     {
    11.         var selected = Selection.activeGameObject;
    12.         if (!selected)
    13.             return;
    14.  
    15.         if (!selected.TryGetComponent<Animator>(out var animator))
    16.             return;
    17.  
    18.         var skeletons=animator.avatar?.humanDescription.skeleton;
    19.      
    20.         var root = animator.transform;
    21.         var tfs = root.Traverse();
    22.         var dir = new Dictionary<string, Transform>(tfs.Count());
    23.         foreach (var tf in tfs)
    24.         {
    25.             if (!dir.ContainsKey(tf.name))
    26.                 dir.Add(tf.name, tf);
    27.         }
    28.  
    29.         foreach (var skeleton in skeletons)
    30.         {
    31.             if (!dir.TryGetValue(skeleton.name, out var bone))
    32.                 continue;
    33.  
    34.             bone.localPosition = skeleton.position;
    35.             bone.localRotation = skeleton.rotation;
    36.             bone.localScale = skeleton.scale;
    37.         }
    38.     }
    39. }
    40.  
     
  20. cathpeta61

    cathpeta61

    Joined:
    Feb 8, 2022
    Posts:
    1
    Thank you very much for the advice, it's really nice to have shared your knowledge.
     
    Viniterra likes this.
  21. jeromeWork

    jeromeWork

    Joined:
    Sep 1, 2015
    Posts:
    429
    Looks useful, but what's the Traverse() method in your code?
     
    ArawnDev likes this.
  22. binaray

    binaray

    Joined:
    Oct 19, 2021
    Posts:
    1
    Stumbled upon this thread while finding ways to reset a model created not in a T-pose to a T-pose.
    For my case I needed to do this to synchronize rotations with a kinect.

    The solution I found was to enforce T-pose under avatar configuration and turning the model there into a prefab. This creates a prefab in T-pose.
    upload_2022-4-11_16-51-1.png
     
    PolygonPros likes this.
  23. adishee

    adishee

    Joined:
    Jun 2, 2020
    Posts:
    8
    Best
     
  24. Raccoonteur

    Raccoonteur

    Joined:
    Jun 4, 2017
    Posts:
    23
    After trying maka's code above and noticing it reset every parameter on every single bone on my avatar including non-humanoid ones such as ears and tails that I'd manually posed in the editor, I came up with this alternative method.

    This code alters only what is needed to correct the bicycle pose. It doesn't change the scale of any of the bones and resets only the rotations of the humanoid bones, and the position of the hips.

    Be aware that it doesn't play nice with undo, so save your scene before you test it. I'm not sure how to make that work.

    To use it, put this script in your Editor folder, then select the avatar in the scene and run the script from the menu under Tools/Enforce T-Pose.

    The avatar must have an animator assigned to it.


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5. using System.Linq;
    6. using System;
    7.  
    8. public class ForceTPose
    9. {
    10.  
    11.     // This method fixes an avatar which is stuck in a bicycle pose.
    12.     // It alters only those bones that are in a typical humanoid armature, so ears and tail will be unaffected.
    13.     // For most bones, only the rotation will be reverted to the T-pose, but for the hips, the position needs to be reset as well.
    14.  
    15.     [MenuItem("Tools/Enforce T-Pose")]
    16.     static void TPose()
    17.     {
    18.         GameObject selected = Selection.activeGameObject;
    19.  
    20.         if (!selected) return; // If no object was selected, exit.
    21.         if (!selected.TryGetComponent<Animator>(out Animator animator)) return; // If the selected object has no animator, exit.
    22.         if (!animator.avatar) return;
    23.  
    24.         SkeletonBone[] skeletonbones = animator.avatar?.humanDescription.skeleton; // Get the list of bones in the armature.
    25.  
    26.         foreach (SkeletonBone sb in skeletonbones) // Loop through all bones in the armature.
    27.         {
    28.           foreach (HumanBodyBones hbb in Enum.GetValues(typeof(HumanBodyBones)))
    29.           {
    30.             if (hbb != HumanBodyBones.LastBone)
    31.             {
    32.  
    33.               Transform bone = animator.GetBoneTransform(hbb);
    34.               if (bone != null) {
    35.  
    36.                 if (sb.name == bone.name) // If this bone is a normal humanoid bone (as opposed to an ear or tail bone), reset its transform.
    37.                 {
    38.  
    39.                   // The bicycle pose happens when for some reason the transforms of an avatar's bones are incorectly saved in a state that is not the t-pose.
    40.                   // For most of the bones this affects only their rotation, but for the hips, the position is affected as well.
    41.                   // As the scale should be untouched, and the user may have altered these intentionally, we should leave them alone.
    42.  
    43.                   if (hbb == HumanBodyBones.Hips) bone.localPosition = sb.position;
    44.                   bone.localRotation = sb.rotation;
    45.                   //bone.localScale = sb.scale;
    46.  
    47.                   // An alternative to setting the values above would be to revert each bone to its prefab state like so:
    48.                   // RevertObjectOverride(boneT.gameObject, InteractionMode.UserAction); // InteractionMode.UserAction should save the changes to the undo history.
    49.  
    50.                   // Though this may only work if the object actually is a prefab, and it would overwrite any user changes to scale or position, and who knows what else.
    51.  
    52.                   break; // We found a humanbodybone that matches, so we need not check the rest against this skeleton bone.
    53.  
    54.                 }
    55.  
    56.               }    
    57.             }
    58.           }
    59.  
    60.         }
    61.  
    62.     }
    63.  
    64. }
     
    Last edited: Oct 6, 2022
  25. unity_3kM51KxKsrnG2A

    unity_3kM51KxKsrnG2A

    Joined:
    Oct 5, 2022
    Posts:
    1

    I LOVE YOU! I just spend 8 hours modelling animating, got to the animations when i did a tired play and messed up my posing and had no way to revert lol. this seems to have fixed my project and many future ones :)
     
  26. tjvenne

    tjvenne

    Joined:
    Jan 8, 2023
    Posts:
    1
    THANK YOU THANK YOU!!!!! This fixes the Bicycle pose that Gogoloco ends up applying to any of my avatars in VRChat unity!!!!
     
  27. adrilee

    adrilee

    Joined:
    Mar 4, 2022
    Posts:
    1
    another success story here. thank you!
     
  28. bennes4

    bennes4

    Joined:
    Jan 22, 2013
    Posts:
    6
    Thank You !!!
     
  29. darketernal666666

    darketernal666666

    Joined:
    Dec 22, 2020
    Posts:
    11
    So, what if it's not a FBX, but a prefab that is not in T-POSE, my FBX is in T-Pose, but the corresponding model is just standing with the hands next to it's body. Is there any way to fix that? The legs are not in the original position like the T-POSE either.
     
  30. calpolican

    calpolican

    Joined:
    Feb 2, 2015
    Posts:
    427
    For reference future reference, if anyone is a bit lost:
    if you want a T-Pose, just set all the joint rotations to 0.
    In case you had a pose and you lost it, as JotaRata said, you just need to rever the prefab values. But remember: only for the rotations.
    Never touch either the scale nor the position of the joints.
     
  31. KieeeShadow

    KieeeShadow

    Joined:
    Nov 3, 2018
    Posts:
    1
    I simple method I found is to play your scene with an animation controller with whatever pose (A-Pose, T-Pose, ect) and then create a new prefab while the scene is running and your character is in that pose. When You stop playing, the model should still be in that pose. If it's not, then remove the character from your scene and drag in the new prefab.