Я пытаюсь смоделировать эффект Доплера в игре (игра в автомобильные гонки). Я не использую определенную звуковую библиотеку, которая имитирует эффект, у меня есть только функция обратного вызова, где я смешиваю данные.
Я уже разобрался, как изменить частоту сэмпла в функции микшера.
То, что я не знаю, это то, насколько частота должна меняться в зависимости от положения игрока и эмиттера и его скорости.
Вот что у меня есть в игре:
//player
vec3 p.pos;
vec3 p.vel;
//emitter
vec3 e.pos;
vec3 e.vel;
1) Согласно википедии , соотношение между излучаемой частотой и наблюдаемой частотой определяется как:
float f = (c + vr) / (c + vs) * fo
где c - постоянная, скорость в среде (обычно большое число) vs и vr - скорости источника и приемника относительно среды.
так что я думаю :
float vr = p.vel.length; //player speed
float vs = e.vel.length; //emitter speed
но я думаю, что это неправильно, это не приведет к какому-либо изменению частоты, например: если vr = 0
(игрок не двигается), а излучатель имеет постоянную скорость, то vr
и не vs
изменится (пока они должны).
Может быть, я должен рассчитать скорость игрока относительно скорости излучателя?
как это :
relative_speed = distance(p.pos + p.vel, e.pos + e.vel) -
distance(p.pos, e.pos);
тогда как vr
и vs
надо кормить?
2) В википедии также приведена другая формула для имитации воздействия транспортного средства, которое транспортное средство проезжает мимо наблюдателя:
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); ?
однако эта формула предполагает, что приемник не двигается, что здесь не так. если игрок и эмиттер движутся с одинаковой скоростью (или небольшой разницей), эффект допплера не должен быть. эта функция также характерна для одного случая, я полагаю, что окончательная формула должна быть такой же, независимо от ситуации.
РЕДАКТИРОВАТЬ: я пытаюсь найти правильную формулу, используя сообщение 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:
Для тех, кто заинтересован, вот окончательная формула:
vec2 dist = vs.pos - vr.pos;
vr,r = dotproduct(vr.vel, dist) / length(dist)
vs,r = dotproduct(vs.vel, dist) / length(dist)
ПРИМЕЧАНИЕ: здесь используется векторная проекция, описанная здесь :
тогда vr,s
и vs,r
нужно вводить в первую формулу википедии:
Я протестировал его, и он успешно работает, обеспечивая отличные результаты.