게임에서 도플러 효과를 어떻게 시뮬레이션합니까?


14

게임 (자동차 경주 게임)에서 도플러 효과를 시뮬레이션하려고합니다. 효과를 시뮬레이션하는 특정 사운드 라이브러리를 사용하지 않고 데이터를 혼합하는 콜백 기능 만 있습니다.

믹서 기능에서 샘플 주파수를 변경하는 방법을 이미 알아 냈습니다.

내가 모르는 것은 플레이어와 이미 터 위치와 속도에 따라 주파수가 얼마나 바뀌어야 하는가입니다.

게임에서 내가 가진 것은 다음과 같습니다.

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

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

1) Wikipedia 에 따르면 방출 주파수와 관측 주파수의 관계는 다음과 같습니다.

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(플레이어 해달라고 이동을)과 에미는 일정한 속도로 가지고 vrvs(있는 동안 그들이해야) 늘 변화.

어쩌면 이미 터의 속도와 상대적으로 플레이어의 속도를 계산해야합니까?

이처럼 :

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,svs,r제 위키 식 주입한다 :

여기에 이미지 설명을 입력하십시오

나는 그것을 테스트하고 성공적으로 작동하여 훌륭한 결과를 제공합니다.


3
소스의 실제 움직임을 수신기에 대한 움직임으로 대체하여 수신기가 움직이지 않는 것으로 가정하는 공식을 조정할 수 있습니다.
yoozer8

답변:


9

1) 두 객체가 같은 라인에서 움직이고 있다고 가정합니다 (이것은 연결된 위키 백과 페이지에 설명되어 있습니다).이 상황에서 일정한 속도로 주파수 시프트는 일정합니다. 주파수 편이가 변하기 위해서는 Vs, SR 축과 동일하지만 동일하지 않은 상황에 대해 상대 속도가 변해야 한다.

그러나 공식 2)는 오해의 소지 Vr가있다 Vs,r. 즉, 소스 속도의 방사상 / 상대 성분 으로 읽어야한다 .

도플러 효과는 속도에만 의존하므로 SR 축을 찾으려면 위치 만 필요합니다.

편집 : 속도를 계산하는 데 도움이 되며 수식 1과 함께 수량 Vs,rVr,r수량 을 사용해야합니다 .

도플러 편이의 상대 속도


네 대답 (그리고 사진)에 감사드립니다. 많은 도움이됩니다. 이제 모든 것이 분명합니다. 공식 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

첫 번째 게시물을 편집하고 올바른 형식으로 수식을 추가했습니다. 당신은 그들을 확인할 수 있습니까? (처음으로 gamedev stackexchange를 사용합니다. 응답으로 라인 리턴을 유지하지 않으며 해당 주석이 5 분 후에 잠겨 있다는 것을
몰랐습니다

@ user1083855 그렇습니다. 더 간단하고 빠르게 만드는 한 가지 방법은 Jim의 제안을 따르고 공식 2)를 상대 이동으로 사용하는 것입니다. 실제 도플러 효과는 사운드 매체 (공기)에 대한 두 엔티티의 속도에 달려 있기 때문에 실제로는 동일하지 않다고 생각하지만 게임 상황에서는 아마도 충분히 가깝고 값 비싼 코스 작업을 절약 할 수 있습니다.
SkimFlux

글쎄, 실제로 vr, r vs, r을 찾는 훨씬 쉬운 방법을 찾았습니다. en.wikipedia.org/wiki/Vector_projection
tigrou

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

Btw.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.