Skip to content

Instantly share code, notes, and snippets.

@TigerHix
Created July 17, 2023 01:31
Show Gist options
  • Save TigerHix/8413f8e10e508f37bb946d8802ee4e0b to your computer and use it in GitHub Desktop.
Save TigerHix/8413f8e10e508f37bb946d8802ee4e0b to your computer and use it in GitHub Desktop.
using Cysharp.Threading.Tasks;
using RootMotion.FinalIK;
using UnityEngine;
using Warudo.Core;
using Warudo.Core.Attributes;
using Warudo.Core.Utils;
using Warudo.Plugins.Core;
using Warudo.Plugins.Core.Assets.Character;
using Object = UnityEngine.Object;
namespace Playground {
[AssetType(Id = "CharacterPoser")]
public class CharacterPoserAsset : CharacterDaemonAsset {
public bool IsPosing { get; private set; } = false;
private Transform poserRoot;
private VRIK vrik;
private Transform headTarget;
private Transform pelvisTarget;
private Transform leftHandTarget;
private Transform rightHandTarget;
private Transform leftFootTarget;
private Transform rightFootTarget;
[Trigger]
[HiddenIf(nameof(HideEnterPoseMode))]
public async void EnterPoseMode() {
if (IsPosing) return;
await UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate);
CharacterDaemon.GameObject.transform.position = Character.MainTransform.position;
CharacterDaemon.GameObject.transform.rotation = Character.MainTransform.rotation;
for (var i = 0; i < (int)HumanBodyBones.LastBone; i++) {
var bt = CharacterDaemon.Animator.GetBoneTransform((HumanBodyBones)i);
if (bt != null) {
bt.localRotation = Character.EndOfFrameBoneRotations[i];
if (i == (int) HumanBodyBones.Hips) {
bt.localPosition = Character.EndOfFrameBonePositions[i];
}
}
}
vrik = CharacterDaemon.GameObject.GetOrAddComponent<VRIK>();
vrik.AutoDetectReferences();
poserRoot = new GameObject("Poser Root").transform;
headTarget = new GameObject("Poser Head Target").transform;
pelvisTarget = new GameObject("Poser Pelvis Target").transform;
leftHandTarget = new GameObject("Poser Left Hand Target").transform;
rightHandTarget = new GameObject("Poser Right Hand Target").transform;
leftFootTarget = new GameObject("Poser Left Foot Target").transform;
rightFootTarget = new GameObject("Poser Right Foot Target").transform;
headTarget.SetParent(poserRoot.transform);
pelvisTarget.SetParent(poserRoot.transform);
leftHandTarget.SetParent(poserRoot.transform);
rightHandTarget.SetParent(poserRoot.transform);
leftFootTarget.SetParent(poserRoot.transform);
rightFootTarget.SetParent(poserRoot.transform);
bool Copy(HumanBodyBones bone, Transform to) {
var hasTransform = Character.Animator.GetBoneTransform(bone) != null;
if (!hasTransform) return false;
to.position = Character.EndOfFrameBoneWorldPositions[(int)bone];
to.rotation = Character.EndOfFrameBoneWorldRotations[(int)bone];
return true;
}
Copy(HumanBodyBones.Head, headTarget);
Copy(HumanBodyBones.Hips, pelvisTarget);
Copy(HumanBodyBones.LeftHand, leftHandTarget);
Copy(HumanBodyBones.RightHand, rightHandTarget);
if (!Copy(HumanBodyBones.LeftToes, leftFootTarget)) Copy(HumanBodyBones.LeftFoot, leftFootTarget);
if (!Copy(HumanBodyBones.RightToes, rightFootTarget)) Copy(HumanBodyBones.RightFoot, rightFootTarget);
vrik.solver.plantFeet = false;
vrik.solver.spine.minHeadHeight = 0f;
vrik.solver.spine.headTarget = headTarget;
vrik.solver.spine.pelvisTarget = pelvisTarget;
vrik.solver.spine.maintainPelvisPosition = 0f;
vrik.solver.spine.neckStiffness = 0f;
vrik.solver.spine.bodyPosStiffness = 0f;
vrik.solver.spine.bodyRotStiffness = 0f;
vrik.solver.spine.moveBodyBackWhenCrouching = 0f;
vrik.solver.leftArm.target = leftHandTarget;
vrik.solver.rightArm.target = rightHandTarget;
vrik.solver.leftLeg.target = leftFootTarget;
vrik.solver.rightLeg.target = rightFootTarget;
vrik.solver.spine.pelvisPositionWeight = 1f;
vrik.solver.spine.pelvisRotationWeight = 1f;
vrik.solver.leftLeg.positionWeight = 1f;
vrik.solver.leftLeg.rotationWeight = 1f;
vrik.solver.rightLeg.positionWeight = 1f;
vrik.solver.rightLeg.rotationWeight = 1f;
vrik.solver.locomotion.weight = 0f;
IsPosing = true;
EnableTransformGizmo();
}
protected bool HideEnterPoseMode() => IsPosing;
[Trigger]
[HiddenIf(nameof(HideExitPoseMode))]
public void ExitPoseMode() {
if (!IsPosing) return;
IsPosing = false;
DisableTransformGizmo();
if (poserRoot != null) {
Object.Destroy(poserRoot.gameObject);
}
if (vrik != null) {
Object.Destroy(vrik);
}
}
protected bool HideExitPoseMode() => !IsPosing;
protected override void OnCreate() {
base.OnCreate();
OnSelectedStateChange.AddListener(selected => {
if (selected) {
EnableTransformGizmo();
} else {
DisableTransformGizmo();
}
});
SetActive(true);
}
protected override void OnDestroy() {
base.OnDestroy();
if (poserRoot != null) {
Object.Destroy(poserRoot.gameObject);
}
DisableTransformGizmo();
}
protected override async void OnCreateCharacterDaemon() {
base.OnCreateCharacterDaemon();
CharacterDaemon.Animancer.enabled = false;
CharacterDaemon.Animator.enabled = true;
}
public override async void OnPostLateUpdate() {
base.OnPostLateUpdate();
if (!CharacterDaemon.IsCreated()) return;
if (IsPosing) {
for (var i = 0; i < (int)HumanBodyBones.LastBone; i++) {
var bt = CharacterDaemon.Animator.GetBoneTransform((HumanBodyBones) i);
var originalBt = Character.Animator.GetBoneTransform((HumanBodyBones) i);
if (bt != null && originalBt != null) {
originalBt.position = bt.position;
originalBt.rotation = bt.rotation;
}
}
}
}
private void EnableTransformGizmo() {
if (!IsSelected || !Active || !IsPosing) return;
var tg = Context.PluginManager.GetPlugin<CorePlugin>().TransformGizmo;
tg.AddTargets(new [] {
headTarget,
pelvisTarget,
leftHandTarget,
rightHandTarget,
leftFootTarget,
rightFootTarget,
}, null, gizmo => {
gizmo.handleLength = .025f;
gizmo.handleWidth = .0004f;
gizmo.planeSize = .005f;
gizmo.triangleSize = .006f;
gizmo.circleDetail = 16;
});
}
private void DisableTransformGizmo() {
if (!IsPosing) return;
var tg = Context.PluginManager.GetPlugin<CorePlugin>().TransformGizmo;
tg.RemoveTargets(new [] {
headTarget,
pelvisTarget,
leftHandTarget,
rightHandTarget,
leftFootTarget,
rightFootTarget,
});
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment