レイトレーシングで音響シミュレーション(Audio Raytracing)

こちらの動画のメモです。

処理は以下のとおりです。

 

メッシュからレイトレース用の BVH を作成

一般的なレイトレースで使われる BVH と特に違いはありません。

bvh

 

HRTF(HRIR) データを読み込み

こちらのデータを使用させていただきました。

GitHub - amini-allight/cipic-hrtf-database: A database of head-related transfer functions created by the Center for Image Processing and Integrated Computing at the University of California in 2001.

HRTF と書いてありますが、中身は HRIR のようです。

データ形式が *.mat だったので以下のライブラリを使用しました。

GitHub - tbeu/matio: MATLAB MAT File I/O Library

 

スピーカーとリスナーを配置

動画ではスピーカーの姿勢は固定しています。

リスナーの位置はゲーム内の頭の姿勢を使っています。

 

リスナーからスピーカーまでの経路をサンプリング

レイを飛ばすとき、2種類の処理を行っています。

  1. リスナーからスピーカーに向けてレイを飛ばして間に障害物がなければ、その向きに最も近い方向に対応したインパルス応答を HRTF(HRIR) から検索して使う
  2. HRTF(HRIR) に含まれる全方向についてリスナーからレイを飛ばし、反射を繰り返す。各反射の点からスピーカーに向けてレイを飛ばして間に障害物がなければ最初の方向に対応するインパルス応答を使う

2. については以下のようになっています。

  • 経路の最後は NEE (Next Event Estimation) を使う
  • 空気中での拡散を再現するため、指数分布を使って求めた距離を最大距離としてレイトレースする。最大距離までの間にレイヒットが見つからなかった場合は最大距離の位置で拡散反射するものとする
  • 障害物に当たった場合は法線方向から半球上のランダムに拡散反射
  • 空気中で拡散した場合はその点から球上のランダムに拡散反射
  • 動画では 5 回で打ち切り

空気中のフォグの濃度が一定であるとして、次にフォグの粒子に当たる距離をランダムにサンプリングする場合、指数分布を使えます。具体的には C++ の std::exponential_distribution を使っています。

指数分布 - Wikipedia

exponential_distribution - cpprefjp C++日本語リファレンス

 

インパルス応答を経路に応じて変更する

上で取得したインパルス応答をもとに経路の長さと音速から求めた時間差分だけずらして、経路長による位相差を再現します。

また、距離に応じて振幅を減衰させます。エネルギーは振幅の二乗だと思うので振幅を距離で割っています。

このときに使う「距離」は、スピーカーまでの最後の距離だけを使っています。他の距離はランダムサンプリングの時点で考慮されていると判断しました。

 

インパルス応答をスピーカーの音に畳み込んで出力

上で変更したインパルス応答を平均化して、スピーカーの音に畳み込みます。

畳み込みには FFT / 逆 FFT と Overlap Save 法を使いました。

重畳加算法 - Wikipedia