2

Scenario:

  • Parent P1 has Child C1
  • Target exists
  • All items' forward vectors face perfectly parallel to the X-Z Plane (pseudo 2D)
  • Positions of all objects are arbitrary
  • Child will never move on its own within Parent's space

Goal:

Rotate P1 exclusively about the Y-Axis to have C1 Face the opposite direction of target's forward vector

enter image description here

Note: Y-Axis Positive would face reader, Negative would go into screen

Implementation:

P1.rotation = Quaternion.LookRotation(-target.forward) * Quaternion.Euler(0, -C1.localEulerAngles.y, 0);

The above seems to work most of the time but breaks randomly and sometimes generates a Zero Vector as the forward. I am inexperienced with Euler Angles and Quaternions so my apologies in advance.

  • If one of the answers below helped please consider [accepting it](https://meta.stackexchange.com/a/5235/405359) – Ruzihm Jan 03 '22 at 21:16

2 Answers2

4

Using some quaternion algebra:

Given this in Unity terms/c#:

Desired child world = Quaternion.LookRotation(-target.forward)
Child local = C1.localRotation`

Given the equation for parent-child rotations:

Desired parent world * Child local = Desired child world 

We want to calculate desired parent world (P1.rotation). Take the above equation and multiply inverse(Child local) on right of both sides and simplify:

DPW * child local * inv(child local) = Desired child world * inv(Child local) 
                Desired parent world = Desired child world * inv(Child local)

Expressing using Unity/C#, you get:

P1.rotation = Quaternion.LookRotation(-target.forward) 
        * Quaternion.Inverse(C1.localRotation);
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
  • 1
    Damn, thank you so much. Ive been trying to figure out why my rotations were always ending slightly off or facing the wrong direction and everywhere I went for information on quaternions has either 1: mentioned only the concept of local/global rotations and their order, but never elaborated, or 2: Was so technical that if I could understand it I wouldn't need the help in the first place. This is the first result I could find that clearly showed the relationship and how you found it in a friendly manner, instantly fixed my problem. I was about to loose my mind. – ZXYNINE Dec 29 '22 at 04:53
  • @ZXYNINE I'm delighted my answer helped you :) – Ruzihm Dec 30 '22 at 08:01
0

A simple way of representing this transform would be the targets rotation plus 180 degrees about the up axis, and that can be expressed as follows:

P1.rotation = target.rotation * Quaternion.AngleAxis(180, Vector3.up);

Note that order does matter, particularly if it is being used in 3D space at all (it would work all the same if the forward vectors are on the same plane in 2D).

Here's how it looks:

Luke Briggs
  • 3,745
  • 1
  • 14
  • 26
  • This only works when C1 has a localRotation of identity. – Ruzihm Jan 03 '22 at 07:20
  • @Ruzihm true; this would have better performance than also factoring in the child's local rotation, so it would come down to if `Child will never move on its own within Parent's space` more generally means "Child is always at a specific rotation relative to its parent" (e.g. because it's a prefab) – Luke Briggs Jan 03 '22 at 07:27
  • even if its a prefab, you still have to account for the child's serialized localRotation if the child has a non-identity localrotation – Ruzihm Jan 03 '22 at 07:28
  • @Ruzihm At which point though, the constant 180 degrees just becomes something else; AxisAngle is both cheap and cachable, if this is something that potentially a large quantity of objects are executing in an update loop – Luke Briggs Jan 03 '22 at 07:32
  • Right, so how might one calculate that "something else"? Would you recommend calculating it manually then assigning a field in the editor? In the same way axisangle is cached, maybe there would be a way to calculate the angle at runtime and cache it – Ruzihm Jan 03 '22 at 07:32
  • @Ruzihm If favouring performance, hardcode it in the prefab, or e.g. `180+C1.localEulerAngles.y` if something generic is really necessary (it often isn't) – Luke Briggs Jan 03 '22 at 07:35