godot Orienting a VR character 2024-11-07What if we just extended the vector coming out from the player’s face?
On an XRCamera3D this would be its -Z vector (a.k.a. -basis.z).
Then we just follow a projection this vector on the world’s XZ plane:
var hmd_forward_xz := -hmd_basis.z * Vector3(1, 0, 1)
var rotation := Basis.looking_at(hmd_forward_xz, Vector3.UP)
This would be the result:
One issue there happens when the player looks down to the ground: With only slight movements of the head it is possible to drastically alter the direction!
Considering a player looking down, the “face” vector can easily be moved to rotate the character in wild ways…
What if we started looking at the +Y vector when looking down? It’s the vector going up from the top of your head. Then even if directly looking at their feet, this vector would more accurately represent the direction our player is facing!
The problem becomes how do we modulate between -Z and +Y?
This is where planes help us: If we consider a plane splitting our head in two from top to bottom then I’d like to orient the character controller alongside it and towards the horizon.
Conveniently, we can represent the horizon as another plane and intersecting them should give us a line: This will be our direction!
The intersection is perpendicular to the normals of both planes: Cross product refresher…
\[\begin{aligned} d = \vec{n}_a \times \vec{n}_b \end{aligned}\]In our case we have:
\[\begin{aligned} Z_{basis} = \vec{X}_{headset} \times (0, 1, 0) \end{aligned}\]We can now build a Basis:
var y := Vector3.UP
var z := hmd_basis.x.cross(y).normalized()
var x := y.cross(z).normalized()
var rotation := Basis(x, y, z)
And this is the new result:
This provides a much more stable orientation for our character controller: We can now look down at our feet and tilt our head without changing our direction!