Próbuję symulować efekt Dopplera w grze (gra wyścigowa). Nie używam konkretnej biblioteki dźwięków, która symuluje efekt, mam tylko funkcję zwrotną, w której miksuję dane.
Już wymyśliłem, jak zmienić częstotliwość próbki w funkcji miksera.
Nie wiem, jak często częstotliwość powinna się zmieniać w zależności od pozycji i prędkości odtwarzacza i emitera.
Oto co mam w grze:
//player
vec3 p.pos;
vec3 p.vel;
//emitter
vec3 e.pos;
vec3 e.vel;
1) Według Wikipedii związek między częstotliwością emitowaną a częstotliwością obserwowaną podaje:
float f = (c + vr) / (c + vs) * fo
gdzie c jest stałą, prędkość w ośrodku (zwykle duża liczba) vs i vr są prędkościami źródła i odbiornika w stosunku do ośrodka.
zgaduję :
float vr = p.vel.length; //player speed
float vs = e.vel.length; //emitter speed
ale myślę, że to źle, nie spowoduje żadnej zmiany częstotliwości, na przykład: jeśli vr = 0
(gracz nie porusza się) i emiter mają stałą prędkość, to vr
i vs
nie zmieni się (podczas gdy powinny).
może powinienem obliczyć prędkość odtwarzacza w stosunku do prędkości emitera?
lubię to :
relative_speed = distance(p.pos + p.vel, e.pos + e.vel) -
distance(p.pos, e.pos);
jak vr
i jak vs
należy karmić?
2) wikipedia podaje także inną formułę symulującą działanie pojazdu, który pojazd mija obserwatora:
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); ?
jednak ta formuła zakłada, że odbiornik się nie porusza, co nie ma miejsca w tym przypadku. jeśli gracz i emiter poruszają się z tą samą prędkością (lub małą różnicą), nie powinno być efektu dopplerowskiego. ta funkcja jest również specyficzna dla jednego przypadku, przypuszczam, że ostateczna formuła powinna być taka sama bez względu na sytuację.
EDYCJA: próbuję znaleźć poprawną formułę, używając 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.
EDYCJA 2:
Dla zainteresowanych, oto ostateczna formuła:
vec2 dist = vs.pos - vr.pos;
vr,r = dotproduct(vr.vel, dist) / length(dist)
vs,r = dotproduct(vs.vel, dist) / length(dist)
UWAGA: wykorzystuje projekcję wektorową, opisaną tutaj :
wtedy vr,s
i vs,r
powinien zostać wstrzyknięty w pierwszą formułę wikipedii:
Przetestowałem to i działa z powodzeniem, zapewniając świetne wyniki.