#1
  1. Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jan 2008
    Location
    Fort Meade, MD
    Posts
    170
    Rep Power
    50

    Question 3D sound, calculating pan


    Anyone out there good with 3D math? Unfortunately, I am definitely not.

    I need a formula to calculate pan, a value between -1 and 1.

    -1 is full sound on left speaker
    0 is equal sound on both speakers
    1 is full sound on right speaker

    Given values are:
    The source's 3D position
    The listener's 3D position
    The "look-at" direction (a normal vector)
    The "up" direction (also normal)

    Any help with this would be greatly appreciated. I know a number of computer languages, so it doesn't matter what language you write in, I am mainly just looking for the math.
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2008
    Posts
    47
    Rep Power
    15
    I'm not sure that there are any free algorithms for placement of sounds in a 3D space for stereo, it'd be really great to know if you've found any, but there are the usual panning laws for placing sound in stereo. Just google for those.
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2008
    Posts
    47
    Rep Power
    15
    Oh in which case just project your sound in 3D space to the horizontal plane of the camera and use those panning laws.
  6. #4
  7. Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jan 2008
    Location
    Fort Meade, MD
    Posts
    170
    Rep Power
    50

    Lightbulb Solution


    For anyone who is interested, I found a couple of friendly mathematicians who helped me come up with the following formula (written in Java):

    Code:
    side = listenerUpVector.cross( listenerLookAtVector );
    side.normalize();
    
    float x = sourcePositionVector.dot( sourcePositionVector.subtract( listenerPositionVector ), side );
    
    float z = sourcePositionVector.dot( sourcePositionVector.subtract( listenerPositionVector ), listenerLookAtVector );
    
    float angle = (float) Math.atan2( x, z );
    
    pan = (float) - Math.sin( angle );
    The above code uses the following Vector3D class:
    Code:
    public class Vector3D
    {
        
    /**
     * The vector's X coordinate.
     */
        public float x;
        
    /**
     * The vector's Y coordinate.
     */
        public float y;
        
    /**
     * The vector's Z coordinate.
     */
        public float z;
    
    /**
     * Constructor:  Places the vector at the origin.
     */
        public Vector3D()
        {
            x = 0.0f;
            y = 0.0f;
            z = 0.0f;
        }
        
    /**
     * Constructor:  Places the vector at the specified 3D coordinates.
     * @param nx X coordinate for the new vector.
     * @param ny Y coordinate for the new vector.
     * @param nz Z coordinate for the new vector.
     */
        public Vector3D( float nx, float ny, float nz )
        {
            x = nx;
            y = ny;
            z = nz;
        }
        
    /**
     * Returns a new instance containing the same information as this one.
     * @return A new Vector3D.
     */
        @Override
        public Vector3D clone()
        {
            return new Vector3D( x, y, z );
        }
        
    /**
     * Returns a vector containing the cross-product: A cross B.
     * @param A First vector in the cross product.
     * @param B Second vector in the cross product.
     * @return A new Vector3D.
     */
        public Vector3D cross( Vector3D A, Vector3D B )
        {
            return new Vector3D(
                                    A.y * B.z - B.y * A.z,
                                    A.z * B.x - B.z * A.x,
                                    A.x * B.y - B.x * A.y );
        }
        
    /**
     * Returns a vector containing the cross-product: (this) cross B.
     * @param B Second vector in the cross product.
     * @return A new Vector3D.
     */
        public Vector3D cross( Vector3D B )
        {
            return new Vector3D(
                                    y * B.z - B.y * z,
                                    z * B.x - B.z * x,
                                    x * B.y - B.x * y );
    
        }
        
    /**
     * Returns the dot-product result of: A dot B.
     * @param A First vector in the dot product.
     * @param B Second vector in the dot product.
     * @return Dot product.
     */
        public float dot( Vector3D A, Vector3D B )
        {
            return( (A.x * B.x) + (A.y * B.y) + (A.z * B.z) );
        }
        
    /**
     * Returns the dot-product result of: (this) dot B.
     * @param B Second vector in the dot product.
     * @return Dot product.
     */
        public float dot( Vector3D B )
        {
            return( (x * B.x) + (y * B.y) + (z * B.z) );
        }
        
    /**
     * Returns the vector represented by: A + B.
     * @param A First vector.
     * @param B Vector to add to A.
     * @return A new Vector3D.
     */
        public Vector3D add( Vector3D A, Vector3D B )
        {
            return new Vector3D( A.x + B.x, A.y + B.y, A.z + B.z );
        }
        
    /**
     * Returns the vector represented by: (this) + B.
     * @param B Vector to add to this one.
     * @return A new Vector3D.
     */
        public Vector3D add( Vector3D B )
        {
            return new Vector3D( x + B.x, y + B.y, z + B.z );
        }
        
    /**
     * Returns the vector represented by: A - B.
     * @param A First vector.
     * @param B Vector to subtract from A.
     * @return A new Vector3D.
     */
        public Vector3D subtract( Vector3D A, Vector3D B )
        {
            return new Vector3D( A.x - B.x, A.y - B.y, A.z - B.z );
        }
        
    /**
     * Returns the vector represented by: (this) - B.
     * @param B Vector to subtract from this one.
     * @return A new Vector3D.
     */
        public Vector3D subtract( Vector3D B )
        {
            return new Vector3D( x - B.x, y - B.y, z - B.z );
        }
        
    /**
     * Changes the length of this vector to 1.0.
     */
        public void normalize()
        {
            double t = Math.sqrt( x*x + y*y + z*z );
            x = (float) (x / t);
            y = (float) (y / t);
            z = (float) (z / t);
        }
    }

IMN logo majestic logo threadwatch logo seochat tools logo