From 6fa82a29d9a10913f8a6248607caaff888059cab Mon Sep 17 00:00:00 2001 From: CaptainSticky <178130360+CaptainSticky@users.noreply.github.com> Date: Mon, 12 Aug 2024 07:45:27 -0700 Subject: [PATCH] Allow head (j_kao) to be posed as part of import by Body Pose and import by Selected. Allow bone positions for head + face bones to be imported when importing by Expression. Allow head (j_kao) position to be restored when importing by Expression. --- Anamnesis/Actor/Pages/PosePage.xaml.cs | 22 ++++++++++--------- .../Actor/Posing/Visuals/SkeletonVisual3d.cs | 12 ++++++++++ Anamnesis/Actor/Refresh/BrioActorRefresher.cs | 2 +- Anamnesis/Files/PoseFile.cs | 11 +++++++--- Anamnesis/Files/SceneFile.cs | 2 +- Anamnesis/Views/TargetSelectorView.xaml.cs | 2 +- 6 files changed, 35 insertions(+), 16 deletions(-) diff --git a/Anamnesis/Actor/Pages/PosePage.xaml.cs b/Anamnesis/Actor/Pages/PosePage.xaml.cs index 180267545..a0b26efde 100644 --- a/Anamnesis/Actor/Pages/PosePage.xaml.cs +++ b/Anamnesis/Actor/Pages/PosePage.xaml.cs @@ -250,22 +250,22 @@ private async Task Refresh() private async void OnImportClicked(object sender, RoutedEventArgs e) { - await this.ImportPose(false, PoseFile.Mode.Rotation); + await this.ImportPose(false, PoseFile.Mode.Rotation, true); } private async void OnImportScaleClicked(object sender, RoutedEventArgs e) { - await this.ImportPose(false, PoseFile.Mode.Scale); + await this.ImportPose(false, PoseFile.Mode.Scale, true); } private async void OnImportSelectedClicked(object sender, RoutedEventArgs e) { - await this.ImportPose(true, PoseFile.Mode.Rotation); + await this.ImportPose(true, PoseFile.Mode.Rotation, false); } private async void OnImportAllClicked(object sender, RoutedEventArgs e) { - await this.ImportPose(false, PoseFile.Mode.All); + await this.ImportPose(false, PoseFile.Mode.All, true); } private async void OnImportBodyClicked(object sender, RoutedEventArgs e) @@ -273,10 +273,9 @@ private async void OnImportBodyClicked(object sender, RoutedEventArgs e) if (this.Skeleton == null) return; - this.Skeleton.SelectHead(); - this.Skeleton.InvertSelection(); + this.Skeleton.SelectBody(); - await this.ImportPose(true, PoseFile.Mode.Rotation); + await this.ImportPose(true, PoseFile.Mode.Rotation, false); this.Skeleton.ClearSelection(); } @@ -296,11 +295,14 @@ private async void OnImportExpressionClicked(object sender, RoutedEventArgs e) } this.Skeleton.SelectHead(); - await this.ImportPose(true, PoseFile.Mode.Rotation | PoseFile.Mode.Scale); + await this.ImportPose(true, PoseFile.Mode.Rotation | PoseFile.Mode.Scale | PoseFile.Mode.Position, true); this.Skeleton.ClearSelection(); } - private async Task ImportPose(bool selectionOnly, PoseFile.Mode mode) + // We want to skip doing the "Facial Expression Hack" if we're posing by selected bones or by body. + // Otherwise, the head won't pose as intended and will return to its original position. + // Not quite !selectedOnly, due to posing by expression actually needing the hack. + private async Task ImportPose(bool selectionOnly, PoseFile.Mode mode, bool doFacialExpressionHack) { try { @@ -351,7 +353,7 @@ private async Task ImportPose(bool selectionOnly, PoseFile.Mode mode) } } - await poseFile.Apply(this.Actor, this.Skeleton, bones, mode); + await poseFile.Apply(this.Actor, this.Skeleton, bones, mode, doFacialExpressionHack); } } catch (Exception ex) diff --git a/Anamnesis/Actor/Posing/Visuals/SkeletonVisual3d.cs b/Anamnesis/Actor/Posing/Visuals/SkeletonVisual3d.cs index 01b8c87c6..abfc813d8 100644 --- a/Anamnesis/Actor/Posing/Visuals/SkeletonVisual3d.cs +++ b/Anamnesis/Actor/Posing/Visuals/SkeletonVisual3d.cs @@ -354,6 +354,18 @@ public bool GetIsBoneParentsHovered(BoneVisual3d? bone) return bone; } + public void SelectBody() + { + this.SelectHead(); + this.InvertSelection(); + + List additionalBones = new List(); + BoneVisual3d? headBone = this.GetBone("j_kao"); + if (headBone != null) + additionalBones.Add(headBone); + this.Select(additionalBones, SkeletonVisual3d.SelectMode.Add); + } + public void SelectHead() { this.ClearSelection(); diff --git a/Anamnesis/Actor/Refresh/BrioActorRefresher.cs b/Anamnesis/Actor/Refresh/BrioActorRefresher.cs index 57925674a..dab0cc24b 100644 --- a/Anamnesis/Actor/Refresh/BrioActorRefresher.cs +++ b/Anamnesis/Actor/Refresh/BrioActorRefresher.cs @@ -60,7 +60,7 @@ public async Task RefreshActor(ActorMemory actor) // Restore current pose skeletonVisual3D = new SkeletonVisual3d(); await skeletonVisual3D.SetActor(actor); - await poseFile.Apply(actor, skeletonVisual3D, null, PoseFile.Mode.All); + await poseFile.Apply(actor, skeletonVisual3D, null, PoseFile.Mode.All, true); }).Start(); } } diff --git a/Anamnesis/Files/PoseFile.cs b/Anamnesis/Files/PoseFile.cs index c990d1c3f..f083f2581 100644 --- a/Anamnesis/Files/PoseFile.cs +++ b/Anamnesis/Files/PoseFile.cs @@ -105,7 +105,7 @@ public void WriteToFile(ActorMemory actor, SkeletonVisual3d skeleton, HashSet? bones, Mode mode) + public async Task Apply(ActorMemory actor, SkeletonVisual3d skeleton, HashSet? bones, Mode mode, bool doFacialExpressionHack) { if (actor == null) throw new ArgumentNullException(nameof(actor)); @@ -154,15 +154,19 @@ public async Task Apply(ActorMemory actor, SkeletonVisual3d skeleton, HashSet