Skip to content

Instantly share code, notes, and snippets.

@emilianavt
Last active April 20, 2025 10:12
Show Gist options
  • Select an option

  • Save emilianavt/3fdc79a8766ff781b86b0eb06aed5084 to your computer and use it in GitHub Desktop.

Select an option

Save emilianavt/3fdc79a8766ff781b86b0eb06aed5084 to your computer and use it in GitHub Desktop.

Revisions

  1. emilianavt revised this gist Mar 11, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion IKRunner.cs
    Original file line number Diff line number Diff line change
    @@ -62,7 +62,7 @@ void Start() {
    try {
    FindInjectionPoint(ref loop, "UnityEngine.PlayerLoop.PreLateUpdate+ConstraintManagerUpdate");
    } catch (Exception e) {
    Debug.LogError("Failed to insert IKRunner inter PlayerLoop: " + e);
    Debug.LogError("Failed to insert IKRunner into PlayerLoop: " + e);
    }
    PlayerLoop.SetPlayerLoop(loop);
    PreConstraintIKRunner.ready = found;
  2. emilianavt revised this gist Mar 11, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion IKRunner.cs
    Original file line number Diff line number Diff line change
    @@ -7,7 +7,7 @@

    // Disable IK and TwistRelaxers and set them on this to have them run before constraints and particle systems are evaluated.
    // Only one instance of IKRunner is possible, but it should be easy enough to extend.
    // Remember to call Start() on the TwistRelaxers once if they are disabled from the beginning.
    // Remember to call Start() on the TwistRelaxers once if they are disabled from the beginning. The IK may also need manual initialization.
    public class IKRunner : MonoBehaviour
    {
    public IK ik;
  3. emilianavt revised this gist Mar 9, 2021. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions IKRunner.cs
    Original file line number Diff line number Diff line change
    @@ -7,6 +7,7 @@

    // Disable IK and TwistRelaxers and set them on this to have them run before constraints and particle systems are evaluated.
    // Only one instance of IKRunner is possible, but it should be easy enough to extend.
    // Remember to call Start() on the TwistRelaxers once if they are disabled from the beginning.
    public class IKRunner : MonoBehaviour
    {
    public IK ik;
    @@ -77,10 +78,10 @@ void IKUpdate() {
    if (ik != null) {
    ik.GetIKSolver().Update();
    foreach (var relaxer in twistRelaxers)
    //if (relaxer.ik == null) {
    if (relaxer.ik == null) {
    foreach (var solver in relaxer.twistSolvers)
    solver.Relax();
    //}
    }
    }
    }
    }
  4. emilianavt revised this gist Mar 9, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions IKRunner.cs
    Original file line number Diff line number Diff line change
    @@ -77,10 +77,10 @@ void IKUpdate() {
    if (ik != null) {
    ik.GetIKSolver().Update();
    foreach (var relaxer in twistRelaxers)
    if (relaxer.ik == null) {
    //if (relaxer.ik == null) {
    foreach (var solver in relaxer.twistSolvers)
    solver.Relax();
    }
    //}
    }
    }
    }
  5. emilianavt revised this gist Feb 17, 2021. No changes.
  6. emilianavt created this gist Feb 17, 2021.
    86 changes: 86 additions & 0 deletions IKRunner.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,86 @@
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.LowLevel;
    using RootMotion.FinalIK;

    // Disable IK and TwistRelaxers and set them on this to have them run before constraints and particle systems are evaluated.
    // Only one instance of IKRunner is possible, but it should be easy enough to extend.
    public class IKRunner : MonoBehaviour
    {
    public IK ik;
    public List<TwistRelaxer> twistRelaxers = new List<TwistRelaxer>();

    private bool found = false;

    bool FindInjectionPoint(ref PlayerLoopSystem system, string target) {
    if (system.type != null && system.type.ToString() == target) {
    return true;
    }
    if (system.subSystemList == null)
    return false;
    found = false;
    for (int i = 0; i < system.subSystemList.Length; i++) {
    found = found || FindInjectionPoint(ref system.subSystemList[i], target);
    }
    if (found) {
    PlayerLoopSystem[] newLoop = new PlayerLoopSystem[system.subSystemList.Length + 1];
    int j = 0;
    for (int i = 0; i < system.subSystemList.Length; i++) {
    if (system.subSystemList[i].type.ToString() == target) {
    newLoop[j] = PreConstraintIKRunner.GetNewSystem();
    j++;
    }
    newLoop[j++] = system.subSystemList[i];
    }
    system.subSystemList = newLoop;
    }
    return false;
    }

    public struct PreConstraintIKRunner {
    public static bool ready = false;
    public static IKRunner ikRunner;
    public static PlayerLoopSystem GetNewSystem() {
    return new PlayerLoopSystem() {
    type = typeof(PreConstraintIKRunner),
    updateDelegate = UpdateFunction
    };
    }

    public static void UpdateFunction() {
    ikRunner.IKUpdate();
    }
    }

    void Start() {
    PreConstraintIKRunner.ikRunner = this;
    if (!PreConstraintIKRunner.ready) {
    var loop = PlayerLoop.GetCurrentPlayerLoop();
    try {
    FindInjectionPoint(ref loop, "UnityEngine.PlayerLoop.PreLateUpdate+ConstraintManagerUpdate");
    } catch (Exception e) {
    Debug.LogError("Failed to insert IKRunner inter PlayerLoop: " + e);
    }
    PlayerLoop.SetPlayerLoop(loop);
    PreConstraintIKRunner.ready = found;
    }
    }

    void Update() {
    if (ik != null)
    ik.GetIKSolver().FixTransforms();
    }

    void IKUpdate() {
    if (ik != null) {
    ik.GetIKSolver().Update();
    foreach (var relaxer in twistRelaxers)
    if (relaxer.ik == null) {
    foreach (var solver in relaxer.twistSolvers)
    solver.Relax();
    }
    }
    }
    }