Tôi đang cố gắng mô phỏng hiệu ứng doppler trong một trò chơi (một trò chơi đua xe). Tôi không sử dụng một thư viện âm thanh cụ thể mô phỏng hiệu ứng, tôi chỉ có chức năng gọi lại nơi tôi trộn dữ liệu.
Tôi đã tìm ra cách thay đổi tần số của một mẫu trong chức năng trộn.
Điều tôi không biết là tần số sẽ thay đổi bao nhiêu tùy thuộc vào vị trí và tốc độ phát của người chơi và người phát.
Đây là những gì tôi có trong trò chơi:
//player
vec3 p.pos;
vec3 p.vel;
//emitter
vec3 e.pos;
vec3 e.vel;
1) Theo wikipedia , mối quan hệ giữa tần số phát ra và tần số quan sát được đưa ra bởi:
float f = (c + vr) / (c + vs) * fo
nơi c là một hằng số, vận tốc trong môi trường (thường là một số lượng lớn) vs và vr là nguồn và máy thu vận tốc tương đối so với trung bình.
vì vậy tôi đoán:
float vr = p.vel.length; //player speed
float vs = e.vel.length; //emitter speed
nhưng tôi nghĩ sai của nó, nó sẽ không tạo ra bất kỳ thay đổi trong tần số, cho ví dụ: nếu vr = 0
(máy nghe nhạc dont di chuyển) và emitter có tốc độ không đổi, sau đó vr
và vs
sự thay đổi sẽ không (trong khi họ cần).
Có lẽ tôi nên tính vận tốc của người chơi tương đối với vận tốc của bộ phát?
như thế này :
relative_speed = distance(p.pos + p.vel, e.pos + e.vel) -
distance(p.pos, e.pos);
Sau đó nên làm thế nào vr
và vs
nên cho ăn?
2) wikipedia cũng đưa ra một công thức khác để mô phỏng hiệu ứng của một phương tiện mà phương tiện đi qua người quan sát:
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); ?
tuy nhiên, công thức này giả sử người nhận không di chuyển, đây không phải là trường hợp ở đây. nếu người chơi và bộ phát di chuyển cùng tốc độ (hoặc chênh lệch nhỏ), sẽ không có hiệu ứng doppler. Hàm này cũng đặc trưng cho một trường hợp, tôi cho rằng công thức cuối cùng sẽ giống như không có tình huống nào.
EDIT: Tôi đang cố gắng tìm công thức chính xác, sử dụng bài đăng 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:
Đối với những người quan tâm, đây là công thức cuối cùng:
vec2 dist = vs.pos - vr.pos;
vr,r = dotproduct(vr.vel, dist) / length(dist)
vs,r = dotproduct(vs.vel, dist) / length(dist)
LƯU Ý: nó sử dụng phép chiếu vector, được mô tả ở đây :
sau đó vr,s
và vs,r
nên được tiêm trong công thức wikipedia đầu tiên:
Tôi đã thử nghiệm nó và nó hoạt động thành công, cung cấp kết quả tuyệt vời.