[openal] [MATH] - A few questions about how I can rotate the listener?

Chris Robinson chris.kcat at gmail.com
Sat Mar 27 08:00:10 EDT 2021


On Fri, 26 Mar 2021 20:50:41 +0000
WSean <s.tolstoyevski at gmail.com> wrote:

> If we think I am a player now, I will turn left with the mouse. So I 
> want the source to be in front of me after I return to left. And a 
> little above.
> The sound should come from above because the Z-axis is positive
> (2.231).
> 
> I don't understand how I can turn the listener.
> 
> In the first case, I want to get the sound on my left in front of me.
> 
> What is the mathematical formula here?

The listener can be turned by using the listener's AL_ORIENTATION
property. It's 6 floats, representing 2 direction vectors, typically
called the 'at' and 'up' vectors. By default, it's:

float orientation[6] = {
    0.0f,  0.0f, -1.0f, // 'at'
    0.0f,  1.0f,  0.0f, // 'up'
};
alListenerfv(AL_ORIENTATION, orientation);

This means the front of the listener is facing forward (along -Z), and
the top of the listener is pointing upward (along +Y). To make the
listener face directly left, the at vector would be changed to indicate
left (along -X):

float orientation[6] = {
   -1.0f,  0.0f,  0.0f, // 'at'
    0.0f,  1.0f,  0.0f, // 'up'
};

Now the front of the listener is pointing left (along -X), so any sounds
to the left of the listener's position is heard as being in front, and
the top of the listener remains pointing upward.

When you're just turning left and right, the orientation can be
calculated by the sine and cosine of the facing angle:

float orientation[6] = {
   sin(angle), 0.0f, -cos(angle), // 'at'
         0.0f, 1.0f,        0.0f, // 'up'
};

where an angle of 0 is facing forward (along -Z), positive values turn
right/clockwise, and negative values turn left/counter-clockwise.

> * * *
> This was about the x and y axis.
> 
> Another question:
> 
> There is a helicopter in the sky. It's flying.
> For example the z value is 15 .
> Normally I look straight ahead. The sound  must come from above.
> But I want to raise my head and return to the helicopter. It's like a 
> player who wants to take Helicopter into aim.
> I don't really understand this vector.

This gets a fair bit more complicated to explain, and I'm not sure I
can do a good job. Normally an application would internally track what
the facing orientation is for the player, camera, and/or listener, be
it a 3x3 rotation matrix, or a quaternion, or yaw, pitch, and roll
angles. You can use that to transform the default 'at' and 'up' vectors
to get the orientation vectors for the OpenAL listener.

If you don't have that, then you'll need to do something else. For the
'at' vector, the calculation for facing a specific object is simple,
just normalize the position of the thing to look at from the listener
position:

float atvector[3] = {
    source_pos[0] - listener_pos[0],
    source_pos[1] - listener_pos[1],
    source_pos[2] - listener_pos[2]
};
normalize(atvector);

float orientation[6] = {
   atvector[0], atvector[1], atvector[2], // 'at'
   ...
};

The 'up' vector is not so simple; it needs to be at a 90-degree angle
from the 'at' vector, and it dictates the relative up/down/left/right
directions. Presuming the listener will always be up-right (not tilted
to the side, or upside-down), the "simple" way I've seen it handled is
to take the cross-product of the desired 'at' vector and the original up
vector (i.e. 0,1,0) to generate a scaled 'side' vector, then normalize
the side vector and recalculate a new up vector by taking the
cross-product of the side vector and the 'at' vector:

float atvector[3] = {
    source_pos[0] - listener_pos[0],
    source_pos[1] - listener_pos[1],
    source_pos[2] - listener_pos[2]
};
normalize(atvector);
float upvector[3] = { 0.0f, 1.0f, 0.0f };

// side = at x up
float side[3];
cross_product(side, atvector, upvector);
normalize(side);

// up = side x at
cross_product(upvector, side, atvector);

float orientation[6] = {
   atvector[0], atvector[1], atvector[2], // 'at'
   upvector[0], upvector[1], upvector[2], // 'up'
};

But beware: this won't work if you look straight up or down. If it gets
too close to being straight up or down, calculating the side vector
using the cross-product can be unstable or fail, and you'll need to do
something else for the up or side vector.

I hope this is somewhat helpful, or at least understandable. If
something's still not clear or if you have other questions, feel free
to ask.


More information about the openal mailing list