Ship Turret rotate towards target in Parent Space?

I have a parent entity, and a child entity. Ship and Turret.
The turret acquires a target, in world space.
It rotates towards the target, using Vector3.Slerp( turret_forwards, target_direction, percent )

That's all fine. But.

When I want to set the new rotation for the given turret, I want to set the rotation in Parent Space. However, when I do " ref Rotation rotation " rotation.Value = new_direction it sets the rotation in World Space.

I assume I'm missing something basic here?
How do I set local to parent rotations in ECS?

Example code ; I stripped out everything except the bare minimum requirements of the system ( ignoring the vector slerping which is perfectly fine ). Any help is greatly appreciated.

     ForEach((ref Rotation rotation, in COTurret turret, in COUnitTargeting targeting, in LocalToWorld localToWorld) =>
          if (targeting.targetEntity != Entity.Null)

               float3 toDirection = math.normalize(targeting.relativeTargetPosition); // pos - targ.pos
               float3 up = math.up(); // { 0, 1, 0 }
               rotation.Value = quaternion.LookRotation( toDirection , up ); // Sets in World Space, but it needs to be in Parent space.


Do you mean local space or the parent’s local space?

This would suggest that your entity does not have a parent as normally Rotation is local space and local space only matches world space if there is no parent.

1 Like

Hey Latios.

The Parent’s local space. As in, I want this rotation applied to this entity offset by it’s parent’s current rotation.

Well man that’s what should be happening. Which is exactly why I’m so frustrated.
It has a parent. But the rotation is not offset. Which is why I assume I’m missing something very simple, or mis-using Rotation somehow.

Unless the problem is actually, that I’m accidentally negating the parent’s rotational offset somehow. Which would be hilarious.

I’m getting the feeling you don’t fully understand coordinate spaces as this doesn’t make any sense:

So I am going to assume what you actually want is to convert a world-space rotation into a local space rotation. If the parent is the root, then:

rotation.Value = math.mul(math.inverse(parentRotation), worldRotation);

And also if your turret has some colliders on it then it is going to be “unparented in order to take part in the physics simulation”. Then you might need some trick to in get the parent rotation as well.

I understand it, but I don’t know how to say it precisely. Anyway you understood.

Thanks Vik.

1 Like

@Lapsapnow Here is a system I use:

        protected override void OnUpdate()
            var playerPosition = GetComponent<LocalToWorld>(GetSingletonEntity<CurrentPlayer.CurrentPlayer>()).Position;
            var deltaTime      = Time.DeltaTime;
                             ref Rotation     rotation,
                             ref TargetPlayer targetPlayer,
                             in  Parent       parent,
                             in  LocalToWorld localToWorld
                         ) =>
                             if (!HasComponent<LocalToWorld>(parent.Value)) return;
                             var playerDistance   = playerPosition - localToWorld.Position;
                             var parentLocalToWorld          = GetComponent<LocalToWorld>(parent.Value);
                             var parentRotation   = normalize(parentLocalToWorld.Rotation);
                             var targetingNormal  = mul(parentRotation, targetPlayer.TargetingAreaNormal);
                             var goalRotation     = quaternion.identity;
                             var isInShootingArea = dot(targetingNormal, playerDistance);
                             if (isInShootingArea > 0)
                                 var rotationAxis = mul(parentRotation, targetPlayer.RotationAxis);
                                 var up = parentLocalToWorld.Up;
                                 var direction = -cross(cross(playerDistance, rotationAxis),

                                 var globalRotation =
                                     quaternion.LookRotationSafe(normalize(direction), normalize(up));
                                 goalRotation = mul(inverse(parentRotation), globalRotation);

                             // FIXME: Make this rotation constant instead of slowing down
                             rotation.Value = slerp(rotation.Value, goalRotation, 7 * deltaTime);
                             // rotation.Value = goalRotation;

It has additional checking if the target is on a correct “side” of the turret but you can just ignore this part

1 Like

Thank you very much sir!