Last active
April 2, 2025 05:28
-
-
Save w0wca7a/adfab40a37a89c9082b87162203a6b86 to your computer and use it in GitHub Desktop.
Model rotates head towards camera. Basic component realization for Stride game engine. Needs additional rework.
This file contains hidden or 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
| // Copyright (c) Stride contributors (https://stride3d.net). | |
| // Distributed under the MIT license. | |
| // This component must be attached to Entity with Skeleton (Model component with skeleton) | |
| using Stride.Core; | |
| using Stride.Engine; | |
| using Stride.Core.Mathematics; | |
| using Stride.Rendering; | |
| using Stride.Core.Annotations; | |
| namespace Additionals.Scripts.Animations | |
| { | |
| [DataContract(nameof(FollowHeadRotation))] | |
| [ComponentCategory("Animations")] | |
| [Display("Rotate head towards camera")] | |
| public class FollowHeadRotationComponent : SyncScript | |
| { | |
| [DataMember] | |
| [Display(1)] | |
| public Entity EntityToFollow { get; set; } | |
| [DataMember] | |
| [Display(2)] | |
| public string NeckBoneName { get; set; } = "CC_Base_NeckTwist02"; //"CC_Base_NeckTwist02"; // CATRigSpine3294 for default Stride model | |
| [DataMember] | |
| [Display(3)] | |
| [DataMemberRange(1, 40, 1, 5, 1)] | |
| public float ActivateDistance { get; set; } | |
| [DataMember] | |
| [Display(4)] | |
| public float RotationSpeed { get; set; } = 2; | |
| private static Quaternion originalRotation; | |
| private static ModelNodeTransformation[] nodeTransformation; | |
| private static SkeletonUpdater skeletonUpdater; | |
| private static int? NeckBoneIndex; // 47 for Stride default model | |
| public override void Start() | |
| { | |
| base.Start(); | |
| skeletonUpdater = Entity.Get<ModelComponent>().Skeleton; | |
| if (skeletonUpdater == null) return; | |
| for (int i = 0; i < skeletonUpdater.Nodes.Length; i++) | |
| { if (skeletonUpdater.Nodes[i].Name == NeckBoneName) | |
| { | |
| NeckBoneIndex = i; | |
| } | |
| } | |
| // Bind entity skeleton pose with ModelNodeTransformation | |
| nodeTransformation = skeletonUpdater.NodeTransformations; | |
| // Save original bone Rotation | |
| originalRotation = nodeTransformation[(int)NeckBoneIndex].Transform.Rotation; | |
| } | |
| // I would like to add a rotation and tilt limitation and correction. | |
| // And also check the added animation component and overwrite it. | |
| public override void Update() | |
| { | |
| if (NeckBoneIndex == null) return; | |
| // Get positions | |
| var entityPosition = Entity.Transform.WorldMatrix.TranslationVector; | |
| var entityToFollow = EntityToFollow.Transform.WorldMatrix.TranslationVector; | |
| // Get current bone rotation | |
| var currentBoneRotation = nodeTransformation[(int)NeckBoneIndex].Transform.Rotation; | |
| //nodeTransformation[(int)NeckBoneIndex].Transform.Rotation = targetRotation; | |
| var distance = Vector3.Distance(entityPosition, entityToFollow); | |
| if (distance > ActivateDistance & currentBoneRotation == originalRotation) return; | |
| DebugText.Print("Distance beetween: " + distance, new Int2(40, 120)); | |
| if(distance < ActivateDistance) | |
| { | |
| // Calculate direction and normalize and then rotate bone | |
| var direction = entityToFollow - entityPosition; | |
| direction.Normalize(); | |
| var targetRotation = Quaternion.LookRotation(direction, Vector3.UnitY); | |
| // This may be needed if source skeleton coordinate system is not equal to Stride | |
| // targetRotation *= Quaternion.RotationY(MathUtil.DegreesToRadians(-90)); | |
| var speedFactor = RotationSpeed * (float)Game.UpdateTime.Elapsed.TotalSeconds; | |
| Quaternion.Slerp(ref currentBoneRotation, ref targetRotation, speedFactor, out var newRotation); | |
| nodeTransformation[(int)NeckBoneIndex].Transform.Rotation = newRotation; | |
| return; | |
| } | |
| if (currentBoneRotation != originalRotation) | |
| { | |
| // Turn back to original | |
| var factor = RotationSpeed * (float)Game.UpdateTime.Elapsed.TotalSeconds; | |
| Quaternion.Slerp(ref currentBoneRotation, ref originalRotation, factor, out var newRotation); | |
| nodeTransformation[(int)NeckBoneIndex].Transform.Rotation = newRotation; | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment