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.

Recommended Answers

All 8 Replies

assuming that look at and 'up' are at roughly at right angles; take the cross product of the look-at and up direction. this will give you a vector that points from the characters left to right ( or right to left ). if the look at and up aren't at right angles... this still should work, but you must normalize the result.

now, calculate the normalized vector between the listeners position and the source position.

finally take the dot product of the normalized vector between listener and source and the normalized vector that points left to right.

the dot product between two vectors gives the scalar projection of one vector onto another, when both vectors are normalized, this projection is a number between -1 and 1. If the value comes out backwards ( negative when it should be positive ) reverse the order of operands to the cross product, or of course, just multiply by -1. Test with something visual first, to see the magnitude of difference between different positions, then scale/offset the result according.

S = source position
L = listeners positon
A = look at direction
B = up direction

dot( normalize( cross( A, B ) ), normalize( S - L ) )

assuming that look at and 'up' are at roughly at right angles; take the cross product of the look-at and up direction. this will give you a vector that points from the characters left to right ( or right to left ). if the look at and up aren't at right angles... this still should work, but you must normalize the result.

now, calculate the normalized vector between the listeners position and the source position.

finally take the dot product of the normalized vector between listener and source and the normalized vector that points left to right.

the dot product between two vectors gives the scalar projection of one vector onto another, when both vectors are normalized, this projection is a number between -1 and 1. If the value comes out backwards ( negative when it should be positive ) reverse the order of operands to the cross product, or of course, just multiply by -1. Test with something visual first, to see the magnitude of difference between different positions, then scale/offset the result according.

S = source position
L = listeners positon
A = look at direction
B = up direction

dot( normalize( cross( A, B ) ), normalize( S - L ) )

Thanks for the speedy response! I will try this out.

Thanks again!

I needed this algorithm to instead calculate the vibration panning on an xbox360 controller.

We would have a player in a pitch black room and an object would emit vibrations and the player could track that object down based on if it were on the left or the right of the player.

THERE WAS A BIG PROBLEM HOWEVER
I WAS USING GAMESTUDIO
GAMESTUDIO IS VERY BAD AT PRECISE CALCULATIONS

I thought I was doing the calculation wrong each time I read other people's similar pseudo-code.

5 days later I realized that Gamestudio is just plain stupid at any calculations.

#define SourcePosition vector (vibra_obje.x, vibra_obje.y, vibra_obje.z)
#define ListenerPosition vector (camera.x, camera.y, camera.z)
#define LookatDirection vector (camera.x + cos (camera.pan) * 80000000, camera.y + sin (camera.pan) * 80000000, 0)
#define UpDirection vector (0, 0, 1)

function test_pan ()
{
	/*
	S = source position
	L = listeners positon
	A = look at direction
	B = up direction
	*/
	//dot( normalize( cross( A, B ) ), normalize( S - L ) )
	
	VECTOR cross_LookANDUp;
	vec_cross (cross_LookANDUp, LookatDirection, UpDirection);	
	
	VECTOR S_Subtract_L;
	vec_set (S_Subtract_L, SourcePosition);
	vec_sub (S_Subtract_L, ListenerPosition);
	
	vec_normalize (cross_LookANDUp, 1);
	vec_normalize (S_Subtract_L, 1);
	
	var panning = vec_dot (cross_LookANDUp, S_Subtract_L);
	
	if (panning < 0)
	{
		xbox_ctrl_vibrate (65535, 0);
	}
	else
	{
		xbox_ctrl_vibrate (0, 65535);
	}
}
#define LookatDirection vector (camera.x + cos (camera.pan) * 80000000, camera.y + sin (camera.pan) * 80000000, 0)

Notice that the value above is 80000000
GAMESTUDIO can only comprehend VERY BIG numbers.
Because I tried working with small numbers earlier, GAMESTUDIO had a fit and lost alot of the vital precision.

these codes are really confusing... what is this for?

commented: More useless comments to spam your sig. -4

exactly what the title says

Hi list :)

I've tryed to write panning effect through PhysX engine syntax (c++) :

vDirEYe.cross(camDir,camViewY); 
vDirEYe.normalize();
vCamTarget = trgtV - camV ;
vCamTarget.normalize();

NxReal pPAN = vCamTarget.dot(vCT);

but pPAN is allway positive value !?
thank's for help...

...otherwise, if camViewY is not dynamic, allways = (0,1,0), i find Left pan as negative value and Right as positive !-)
but when if move arround trgtV, the Left pan become Right pan and so on...

I've made a mistake, in my code camViewY was dynamic (update by mouse) instead of be fixed as value(0,1,0)
So now is perfect, Left pan as negative value and Right as positive !-)

Thank's a lot for the post ;-)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.