using System; using System.Linq; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace AIGame.Review { /// Scene-authored, synchronized skinning comparison. No UI/model construction at runtime. public sealed class CharacterAnimationLab : MonoBehaviour { [Serializable] public sealed class Actor { public string label; public GameObject rig; public Transform hips; public Transform rightHand; public SkinnedMeshRenderer renderer; // Optional full target-pose walk derived from the common source // motion. Used where preserving source angles alone crosses feet. public AnimationClip walkingClip; // Optional bind translation adaptation. The shared source clip's // rotation curves and time remain unchanged across characters. public float translationScale = 1f; public Vector3[] translationOffsets = Array.Empty(); public Quaternion[] translationDeltaRotations = Array.Empty(); public int[] rotationParents = Array.Empty(); public Quaternion[] bindRotationCorrections = Array.Empty(); [NonSerialized] public Quaternion[] sampledWorldRotations; [NonSerialized] public Quaternion[] mappedWorldRotations; } public Actor[] actors; public AnimationClip[] clips; public Vector3[] travel; public Camera reviewCamera; public Transform ui; public Material texturedMaterial; public Material clayMaterial; public int motion; public bool playing = true; public bool inPlace = true; public bool textured = true; public float speed = 1f; public float time; public int focus = -1; public int detail; public float yaw; TMP_Text stateText, timeText, pauseText, travelText, materialText, detailText; RectTransform progress; float progressWidth; float zoom = 1f; Vector3 lastMouse; bool dragging; SkinWeights previousWeights; bool changedWeights; bool previousRunInBackground; public float Duration => clips != null && clips.Length > 0 ? clips[motion].length : 1; public int FrameCount => Mathf.RoundToInt(Duration * 30) + 1; void OnEnable() { if (!Application.isPlaying) return; previousWeights = QualitySettings.skinWeights; previousRunInBackground = Application.runInBackground; Application.runInBackground = true; QualitySettings.skinWeights = SkinWeights.Unlimited; changedWeights = true; } void OnDisable() { if (changedWeights) { QualitySettings.skinWeights = previousWeights; Application.runInBackground = previousRunInBackground; } changedWeights = false; } void Awake() { if (!ui) return; var buttons = ui.GetComponentsInChildren