Correctly Changing Listener's Position and Orientation

Started by paulscode, May 26, 2008, 01:50:01

Previous topic - Next topic

paulscode

I tracked down a problem I've been having for a while.  However, I can not figure out how to solve it.  It is related to moving the listener away from the origin.

I place a source somewhere like:
Position: (0, 0, 250)

I place the listener at:
Position: (0, 0, 0)
Look-at: (0, 0, 1)
Up-direction: (0, 1, 0)

Now, I can turn the listener, and the source volume pans between left and right speakers correctly.

However, if I move the listener to:
Position: (0, 0, 200)
Look-at: (0, 0, 201)
Up-direction: (0, 1, 0 )

Now, if I turn the listener, the source doesn't pan between left and right speakers any more.  I suspect it has something to do with the orientation being set incorrectly.  Does anyone have some experience with this, or know of a good tutorial I could read about moving the listener?  All the tutorials I can find cover moving the sources, but not much with moving the listener.

My code for moving the listener currently looks like this:
    private void moveListener( float x, float y, float z )
    {
        float xOffset = x - listenerPosition.get( 0 );
        float yOffset = y - listenerPosition.get( 1 );
        float zOffset = z - listenerPosition.get( 2 );
        
        listenerPosition.put( 0, x );
        listenerPosition.put( 1, y );
        listenerPosition.put( 2, z );
        
        AL10.alListener( AL10.AL_POSITION, listenerPosition );
        
        // Keep the listener facing the same direction by
        // moving the "look at" point by the offset values:
        listenerOrientation.put( 0, listenerOrientation.get( 0 ) + xOffset );
        listenerOrientation.put( 1, listenerOrientation.get( 1 ) + yOffset );
        listenerOrientation.put( 2, listenerOrientation.get( 2 ) + zOffset );
        
        AL10.alListener( AL10.AL_ORIENTATION, listenerOrientation );
    }


For reference:

Listener is initially created using the following code:
    private synchronized void initListener()
    {
        // Listener is at the origin, facing along the z axis, no velocity:
        listenerPosition = BufferUtils.createFloatBuffer( 3 ).put( 
            new float[] { 0.0f, 0.0f, 0.0f } );
        listenerOrientation = BufferUtils.createFloatBuffer( 6 ).put (
            new float[] { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f } );
        listenerVelocity = BufferUtils.createFloatBuffer( 3 ).put (
            new float[] { 0.0f, 0.0f, 0.0f } );
        
        // Flip the buffers, so they can be used:
        listenerPosition.flip();
        listenerOrientation.flip();
        listenerVelocity.flip();
        
        AL10.alListener( AL10.AL_POSITION, listenerPosition );
        AL10.alListener( AL10.AL_ORIENTATION, listenerOrientation );
        AL10.alListener( AL10.AL_VELOCITY, listenerVelocity );
    }


And the listener is turned using the following:
    public void setListenerAngle( float angle )
    {
        float xOffset = -1.0f * (float) Math.sin( angle );
        float zOffset = -1.0f * (float) Math.cos( angle );
        listenerOrientation.put( 0, listenerPosition.get( 0 ) + xOffset);
        listenerOrientation.put( 2, listenerPosition.get( 2 ) + zOffset);
        AL10.alListener( AL10.AL_ORIENTATION, listenerOrientation );
    }


Any ideas what I am doing wrong?  I've tried not changing the listener's orientation at all, and I've also tried changing the listener's up-direction by adding the offset values, but neither of those ideas worked.

paulscode

I believe I have ruled out the moveListener method as being the source of the problem.  I created a test program that put a source at (50, 0, 250), and started the listener at (0,0,0), looking (0,0,1), up (0,1,0).

From there I can call moveListener(0, 0, 250) and the source plays out of the left speaker, or moveListener(100, 0, 250) for the right speaker.  That is exactly what it is should do.

So from that test, it looks like the problem is with the setListenerAngle method.  The math here seems like it should work, though, so what am I missing ???

    public void setListenerAngle( float angle )
    {
        float xOffset = -1.0f * (float) Math.sin( angle );
        float zOffset = -1.0f * (float) Math.cos( angle );
        listenerOrientation.put( 0, listenerPosition.get( 0 ) + xOffset);
        listenerOrientation.put( 2, listenerPosition.get( 2 ) + zOffset);
        AL10.alListener( AL10.AL_ORIENTATION, listenerOrientation );
    }

paulscode

Ok, I don't think the math in setListenerAngle is the problem.  The problem is in the last line, where I tell OpenAL what the listener's orientation is.  Here's why I think that line is the problem:

I created a simple method for setting the listener's orientation manually:

    public void setListenerOrientation( float lookX, float lookY, float lookZ,
                                        float upX, float upY, float upZ )
    {
        listenerOrientation.put( 0, lookX );
        listenerOrientation.put( 1, lookY );
        listenerOrientation.put( 2, lookZ );
        listenerOrientation.put( 3, upX );
        listenerOrientation.put( 4, upY );
        listenerOrientation.put( 5, upZ );

        AL10.alListener( AL10.AL_ORIENTATION, listenerOrientation );
    }


Then I have a source at (50, 0, 250) as in my last example.

When I use:
        mySoundSystem.moveListener( 0, 0, 250 );
        mySoundSystem.setListenerOrientation( 0, 0, 251, 0, 1, 0 );

Sound plays out of the left speaker as expected.

But when I use:
        mySoundSystem.moveListener( 0, 0, 250 );
        mySoundSystem.setListenerOrientation( 0, 0, 249, 0, 1, 0 );

Sound still plays out of the left speaker, even though I should be facing the opposite direction!

This means I obviously do not understand how the listener orientation part of OpenAL works.  Can anyone help explain this to me?  Thanks in advance.

-- EDIT --
My thought is perhaps the lookAt direction needs to represent a normalized vector (distance=1 from the origin), like how the up direction works.  I'll test this theory and let you know what I find out.

-- EDIT #2 --
Yes that appears to be the issue.

When I use:
        mySoundSystem.moveListener( 0, 0, 250 );
        mySoundSystem.setListenerOrientation( 0, 0, 1, 0, 1, 0 );

Then Sound is out of the left speaker.

And when I use:
        mySoundSystem.moveListener( 0, 0, 250 );
        mySoundSystem.setListenerOrientation( 0, 0, -1, 0, 1, 0 );

Then Sound is out of the right speaker.

I'll try changing my code with this in mind, and see if this solves the problem.

paulscode

Problem solved.  Use normalized vectors.  I can't believe it took me this long to figure that out  :-[

Once again, solved my own problem.  I guess it helps to just try and explain something to someone else.  You think of things you hadn't considered before.

Matzon

I experience that a lot too when explaining a problem to a coworker! Thats one of the beauties of discussing stuff on discussion boards - or even more so IRC.