### Thread: 3D sound, calculating pan

1. #### 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. No Profile Picture
Contributing User
Devshed Newbie (0 - 499 posts)

Join Date
Apr 2008
Posts
47
Rep Power
19
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.
3. No Profile Picture
Contributing User
Devshed Newbie (0 - 499 posts)

Join Date
Apr 2008
Posts
47
Rep Power
19
Oh in which case just project your sound in 3D space to the horizontal plane of the camera and use those panning laws.
4. #### 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);
}
}```