Last active
February 8, 2024 10:42
-
-
Save emilianavt/3fdc79a8766ff781b86b0eb06aed5084 to your computer and use it in GitHub Desktop.
This component uses the UnityEngine.LowLevel API to run Final IK things before Unity constraints and particle systems are evaluated.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. | |
// 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; | |
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 into 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(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment