如何在游戏中模拟多普勒效果?


14

我正在尝试在游戏(赛车游戏)中模拟多普勒效果。我没有使用模拟声音效果的特定声音库,只有混合数据的回调函数。

我已经弄清楚了如何在混频器功能中更改采样频率。

我不知道,根据玩家和发射器的位置和速度,频率应该改变多少。

这是我在游戏中所拥有的:

//player 
vec3 p.pos; 
vec3 p.vel;

//emitter 
vec3 e.pos;
vec3 e.vel;

1)根据维基百科,发射频率与观测频率之间的关系为:

float f = (c + vr) / (c + vs) * fo

其中c为常数,介质(通常为大数)中的速度 vsvr是相对于介质的源和接收器速度。

所以我猜:

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);

那么如何vrvs应喂?


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 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. 

编辑2:

对于那些感兴趣的人,这里是最终公式:

vec2 dist = vs.pos - vr.pos;

vr,r = dotproduct(vr.vel, dist) / length(dist)
vs,r = dotproduct(vs.vel, dist) / length(dist)

注意:它使用矢量投影,在这里描述:

投影公式

然后vr,svs,r应将其插入第一个维基百科公式:

在此处输入图片说明

我对其进行了测试,并成功运行了,并提供了不错的结果。


3
您可以通过将源的实际移动替换为相对于接收器的移动来调整假设接收器没有移动的公式。
yoozer8'2

Answers:


9

1)假设两个对象都在同一行上移动-(这在您链接的Wikipedia页面中进行了说明),您的结论是正确的,在这种情况下,如果速度恒定,则频移恒定。为了使频移改变,相对速度需要改变,因此公式2)对于Vs恒定但与SR轴不共线的情况。

但是,公式2)具有误导性:Vr应理解为Vs,r,即源速度的径向/相对分量。

请注意,多普勒效应仅取决于速度,您只需要找到SR轴的位置即可。

编辑:这应该可以帮助您确定速度,您需要使用Vs,rVr,r数量与公式1:

多普勒频移的相对速度


好的,谢谢您的回答(和图片),它很有帮助。现在一切都清楚了,我应该将公式1和2结合在一起。正如您所解释的,当对象不在同一行中时,Formula2将很有用。最后一部分是找出vr,r和vs,r。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)); //是否有更容易/更快的方法来找到它们?//注意vr.vel和vs.vel是向量,SkimFlux图片上的绿色和红色箭头。
tigrou 2012年

我编辑了第一篇文章,并以正确的格式添加了公式。你能检查一下吗?(我第一次使用gamedev stackexchange。我不知道它不会保持行返回作为答复,并且该注释在5分钟后被锁定...)
tigrou 2012年

@ user1083855是的,看起来不错。一种使其更简单/更快的方法是遵循吉姆的建议,并使用公式2)两者之间的相对运动。我认为这并不完全相同,因为真正的多普勒效应取决于两个实体相对于声音介质(空中)的速度,但是在游戏情况下,它可能足够接近并且可以节省您昂贵的cos操作。
SkimFlux,2012年

好吧,实际上我发现了一种更简单的方法来找到vr,r vs,r:en.wikipedia.org/wiki/Vector_projection
tigrou 2012年

0

对于XACT,应指定多普勒音调标量变量,即相对速度,其中1.0是相同速度,但<1.0较慢,而> 1.0则较快

谢谢大家提供的代码,我已将其转移到此C#代码中,其中在屏幕位置和提示之间计算声音。精确地工作

soundElements.ForEach(e =>
            {
                var cuePosition = new Vector3(e.PhysicPosition, 0);
                var distance = cuePosition - ScreenCenter;
                var distanceLength = distance.Length();
                e.Cue.SetVariable("Distance", distanceLength);
                var dopplerPitchScalar = 1.0f;
                if (e.AssociatedBody != null)
                {
                    ///gamedev/23583/how-do-i-simulate-a-doppler-effect-in-a-game
                    var screenVelocity = Vector3.Dot(ScreenVelocity, distance) / distanceLength;
                    var cueVelocity = Vector3.Dot(new Vector3(e.AssociatedBody.LinearVelocity, 0), distance) / distanceLength;
                    var relativeVelocity = screenVelocity - cueVelocity;
                    dopplerPitchScalar = (1f + relativeVelocity / SoundEffect.SpeedOfSound) / (1f - relativeVelocity / SoundEffect.SpeedOfSound);
                    //Console.WriteLine($"C: {ScreenCenter}, V: {ScreenVelocity}, D: {dopplerPitchScalar}");
                }
                e.Cue.SetVariable("DopplerPitchScalar", dopplerPitchScalar);
            });

顺便说一句。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.