// Designed by KINEMATION, 2024. using Kinemation.MotionWarping.Runtime.Core; using Kinemation.MotionWarping.Runtime.Utility; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.Animations; using UnityEngine.Playables; namespace KINEMATION.MotionWarping.Editor.Widgets { public class WarpPosePreviewWidget : IWarpWidgetInterface { private GameObject _warpTracerObject; private Vector3 _basePos; private Quaternion _baseRot; private GameObject _sceneCharacter; private AnimationClipPlayable _previewMotion; private int _phaseSlider = 0; private bool _preview = false; private WarpPoint[] _warpPoints = null; private Dictionary _cachedTransforms = new Dictionary(); private PlayableGraph _playableGraph; private MotionWarpingAsset _motionWarpingAsset; public WarpPosePreviewWidget(MotionWarpingAsset asset) { _motionWarpingAsset = asset; } private void CacheTransforms() { _cachedTransforms.Clear(); Transform[] allChildren = _sceneCharacter.GetComponentsInChildren(); foreach (Transform child in allChildren) { (Vector3, Quaternion) data; data.Item1 = child.localPosition; data.Item2 = child.localRotation; _cachedTransforms[child.name] = data; } } private void ApplyCachedTransforms() { if (_sceneCharacter == null) return; Transform[] allChildren = _sceneCharacter.GetComponentsInChildren(); foreach (Transform child in allChildren) { if (_cachedTransforms.ContainsKey(child.name)) { child.localPosition = _cachedTransforms[child.name].Item1; child.localRotation = _cachedTransforms[child.name].Item2; } } } public void RestorePose() { if (_playableGraph.IsValid()) { _playableGraph.Destroy(); } if (_previewMotion.IsValid()) { _previewMotion.Destroy(); } if (_preview) { ApplyCachedTransforms(); } _cachedTransforms.Clear(); } public void Render() { _sceneCharacter = (GameObject) EditorGUILayout.ObjectField("Character", _sceneCharacter, typeof(GameObject), true); if (_sceneCharacter == null) { EditorGUILayout.HelpBox("Missing Character Reference!", MessageType.Error); return; } Animator animator = _sceneCharacter.GetComponentInChildren(); if (animator == null) { EditorGUILayout.HelpBox("No Animator Found!", MessageType.Error); return; } _warpTracerObject = (GameObject) EditorGUILayout.ObjectField("Source", _warpTracerObject, typeof(GameObject), true); if (_warpTracerObject == null) { EditorGUILayout.HelpBox("Select Warp Tracer game object.", MessageType.Warning); return; } EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); AnimationPlayableOutput playableOutput; if (GUILayout.Button("Play")) { CacheTransforms(); _playableGraph = PlayableGraph.Create("WarpPosePreviewGraph"); playableOutput = AnimationPlayableOutput.Create(_playableGraph, "Animation", animator); _previewMotion = AnimationClipPlayable.Create(_playableGraph, _motionWarpingAsset.animation); playableOutput.SetSourcePlayable(_previewMotion); _preview = true; animator.fireEvents = false; animator.applyRootMotion = false; if (_warpTracerObject.GetComponent() is var tracer) { var result = tracer.Interact(_sceneCharacter); _warpPoints = result.points; } _phaseSlider = -1; } if (GUILayout.Button("Stop")) { _preview = false; animator.Rebind(); animator.fireEvents = true; animator.applyRootMotion = true; _phaseSlider = 0; if (_playableGraph.IsValid()) { _playableGraph.Stop(); _playableGraph.Destroy(); } if (_previewMotion.IsValid()) { _previewMotion.Destroy(); } ApplyCachedTransforms(); } EditorGUILayout.EndHorizontal(); if (!_preview) return; if (_warpPoints == null || _warpPoints.Length != _motionWarpingAsset.warpPhases.Count) { string msg = "MotionWarping: WarpObject points are null or size does not match!"; EditorGUILayout.HelpBox(msg, MessageType.Error); return; } int max = _motionWarpingAsset.warpPhases.Count - 1; int prevSlider = _phaseSlider; _phaseSlider = EditorGUILayout.IntSlider("Phase", _phaseSlider, 0, max); if (_previewMotion.IsValid()) { float time = _motionWarpingAsset.warpPhases[_phaseSlider].endTime; _previewMotion.SetTime(time); } var phase = _motionWarpingAsset.warpPhases[_phaseSlider]; if (prevSlider != _phaseSlider) { _playableGraph.Evaluate(); _sceneCharacter.transform.position = _warpPoints[_phaseSlider].GetPosition(); _sceneCharacter.transform.rotation = _warpPoints[_phaseSlider].GetRotation(); _basePos = _sceneCharacter.transform.position; _baseRot = _sceneCharacter.transform.rotation; var pos = _sceneCharacter.transform.TransformPoint(phase.tOffset); var rot = _sceneCharacter.transform.rotation * Quaternion.Euler(phase.rOffset); _sceneCharacter.transform.position = pos; _sceneCharacter.transform.rotation = rot; } var tDelta = _sceneCharacter.transform.position - _basePos; var tLocalDelta = Quaternion.Inverse(_baseRot) * tDelta; var rLocalDelta = Quaternion.Inverse(_baseRot) * _sceneCharacter.transform.rotation; phase.tOffset = tLocalDelta; phase.rOffset = rLocalDelta.eulerAngles; _motionWarpingAsset.warpPhases[_phaseSlider] = phase; } } }