Estoy tratando de simular el efecto Doppler en un juego (un juego de carreras de autos). No estoy usando una biblioteca de sonido específica que simule el efecto, solo tengo una función de devolución de llamada donde mezclo los datos.
Ya descubrí cómo cambiar la frecuencia de una muestra en la función del mezclador.
Lo que no sé es cuánto debería cambiar la frecuencia dependiendo de la posición y velocidad del jugador y del emisor.
Esto es lo que tengo en el juego:
//player
vec3 p.pos;
vec3 p.vel;
//emitter
vec3 e.pos;
vec3 e.vel;
1) Según Wikipedia , la relación entre la frecuencia emitida y la frecuencia observada viene dada por:
float f = (c + vr) / (c + vs) * fo
donde c es una constante, la velocidad en el medio (generalmente un gran número) vs y vr son las velocidades de origen y receptor en relación con el medio.
así que supongo:
float vr = p.vel.length; //player speed
float vs = e.vel.length; //emitter speed
pero creo que está mal, no producirá ningún cambio en la frecuencia, por ejemplo: si vr = 0
(el jugador no se mueve) y el emisor tienen una velocidad constante, entonces vr
y vs
no cambiarán (mientras deberían).
¿Tal vez debería calcular la velocidad del jugador en relación con la velocidad del emisor?
Me gusta esto :
relative_speed = distance(p.pos + p.vel, e.pos + e.vel) -
distance(p.pos, e.pos);
entonces, ¿cómo vr
y vs
debe ser alimentado?
2) Wikipedia también da otra fórmula para simular el efecto de un vehículo que el vehículo pasa por el observador:
vr = vs * cos(theta);
//theta is angle between observer and emitter
//theta = atan2(e.pos.y-p.pos.y, e.pos.x-p.pos.x); ?
sin embargo, esta fórmula supone que el receptor no se mueve, lo cual no es el caso aquí. Si el jugador y el emisor se mueven a la misma velocidad (o una pequeña diferencia), no debería haber efecto Doppler. Esta función también es específica para un caso, supongo que la fórmula final debería ser la misma sin importar la situación.
EDITAR: estoy tratando de encontrar la fórmula correcta, usando la publicación de SkimFlux:
vr,r = vr.vel * cos(shortest_angle_between ( vr.vel , vs.pos - vr.pos));
vs,r = vs.vel * cos(shortest_angle_between ( vs.vel , vr.pos - vs.pos));
//is there a easier/faster way to find them out ?
//note: vr.vel and vs.vel are vectors, the green and red arrows on SkimFlux picture.
EDIT2:
Para aquellos interesados, aquí está la fórmula final:
vec2 dist = vs.pos - vr.pos;
vr,r = dotproduct(vr.vel, dist) / length(dist)
vs,r = dotproduct(vs.vel, dist) / length(dist)
NOTA: utiliza proyección vectorial, descrita aquí :
entonces vr,s
y vs,r
debería inyectarse en la primera fórmula de Wikipedia:
Lo probé y funciona con éxito, proporcionando excelentes resultados.