Estou tentando simular o efeito doppler em um jogo (um jogo de corrida de carros). Não estou usando uma biblioteca de sons específica que simula o efeito, só tenho uma função de retorno de chamada onde misturo os dados.
Eu já descobri como alterar a frequência de uma amostra na função mixer.
O que eu não sei é quanto a frequência deve mudar dependendo da posição e velocidade do player e do emissor.
Aqui está o que eu tenho no jogo:
//player
vec3 p.pos;
vec3 p.vel;
//emitter
vec3 e.pos;
vec3 e.vel;
1) Segundo a Wikipedia , a relação entre frequência emitida e frequência observada é dada por:
float f = (c + vr) / (c + vs) * fo
onde c é uma constante, a velocidade no meio (geralmente um grande número) vs e vr são as velocidades da fonte e do receptor em relação ao meio.
então eu acho :
float vr = p.vel.length; //player speed
float vs = e.vel.length; //emitter speed
mas acho errado, ele não produzirá nenhuma alteração na frequência, por exemplo: se vr = 0
(o jogador não se move) e o emissor tem velocidade constante, então vr
e vs
não muda (enquanto deveria).
talvez eu deveria calcular a velocidade do jogador em relação à velocidade do emissor?
como isso :
relative_speed = distance(p.pos + p.vel, e.pos + e.vel) -
distance(p.pos, e.pos);
então como vr
e vs
deve ser alimentado?
2) a Wikipedia também fornece outra fórmula para simular o efeito de um veículo que o veículo passa pelo 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); ?
no entanto, essa fórmula supõe que o receptor não se mova, o que não é o caso aqui. se o jogador e o emissor se moverem na mesma velocidade (ou pequena diferença), não haverá efeito doppler. essa função também é específica para um caso, suponho que a fórmula final deva ser a mesma, independentemente da situação.
EDIT: estou tentando encontrar a fórmula correta, usando o SkimFlux post:
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 os interessados, aqui está a 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: usa projeção vetorial, descrita aqui :
então vr,s
e vs,r
deve ser injetado na primeira fórmula da wikipedia:
Eu testei e funciona com sucesso, fornecendo ótimos resultados.