mojoAL icon indicating copy to clipboard operation
mojoAL copied to clipboard

Positional audio isn't correct

Open icculus opened this issue 4 years ago • 5 comments

As for the transition: yes, this code also has problems. It's already an extremely naive approach, and on top of that, there's clearly some incorrect math somewhere causing that jarring transition. Fixing that is on the TODO list (but I'm going to split this comment into a second bug so there's an actual place we're tracking that change).

Originally posted by @icculus in https://github.com/icculus/mojoAL/issues/2#issuecomment-898814119

icculus avatar Aug 14 '21 04:08 icculus

I believe you are overcomplicating your approach to calculating the angle between the "at" and the "position".

I think the correct way is to do the following:

  1. Take the position vector and subtract the listener position, store in a vector called V
  2. Let a = Dot(V, Up)
  3. Remove upwards component of V by doing V = V - a * Up
  4. V will now lie in the plane with your "at" vector
  5. Use the cross product to calculate the angle.

adahlkvist-feral avatar Apr 12 '23 10:04 adahlkvist-feral

		ALfloat V[3];
		SDL_memcpy(V, position, sizeof(V));
		ALfloat a = dotproduct(V, up);

		V[0] -= a * up[0];
		V[1] -= a * up[1];
		V[2] -= a * up[2];

		ALfloat mags = magnitude(at) * magnitude(V);
		ALfloat dot = dotproduct(at, V);
		radians = (mags == 0.0f) ? 0.0f : SDL_acosf(dot / mags);

		if (dot < 0.0f)
		{
			radians = -radians;
		}

adahlkvist-feral avatar Apr 12 '23 11:04 adahlkvist-feral

Actually the above code might not always work, you need to clamp the thing you put into SDL_acosf from -1 to 1 otherwise you get NaN issues when the float rounding goes ever so slightly above 1 sometimes.

adahlkvist-feral avatar Apr 12 '23 12:04 adahlkvist-feral

Upon further reflection, I think the right code would look like this:

	// Get position relative to the listener
	ALfloat V[3];
	SDL_memcpy(V, position, sizeof(V));
	ALfloat a = dotproduct(V, up);

	// Remove upwards component so it lies completely within the horizontal plane.
	V[0] -= a * up[0];
	V[1] -= a * up[1];
	V[2] -= a * up[2];  

	// Calculate angle
	ALfloat mags = magnitude(at) * magnitude(V);
	ALfloat cosAngle = (mags == 0.0f) ? 0.0f : (dotproduct(at, V) / mags);
	cosAngle = fmaxf(fminf(cosAngle, 1.0f), -1.0f);
	radians = SDL_acosf(cosAngle);

	// Get "right" vector
	ALfloat R[3];
	xyzzy(R, at, up);

	// If it's facing right, then it's positive, if it's facing left, then it's negative.
	if (dotproduct(R,V) < 0.0f)
	{
		radians = -radians;
	}
	```

adahlkvist-feral avatar Apr 12 '23 13:04 adahlkvist-feral

A person made a fork with an alternative calculation that appears related to this

https://github.com/Helco/mojoAL/commit/f5db374adc0d1254876450ca97a259ef9990922b

ericoporto avatar Mar 09 '24 13:03 ericoporto