概要
動作確認環境: Godot 4.3+
3Dゲームにおける空間音響は、プレイヤーの没入感を大きく高める要素です。足音が背後から近づいてくる、遠くの爆発音が小さく聞こえる――こうした距離や方向に基づく音の変化を、GodotではAudioStreamPlayer3Dで簡単に実装できます。
本記事では、AudioStreamPlayer3Dの基本設定から減衰モデルの選択、AudioListener3Dの使い分け、ドップラー効果やエリアリバーブまで、3D空間音響の実装に必要な知識をまとめます。
AudioStreamPlayer3Dの基本
3D空間音響を使うための第一歩は、AudioStreamPlayer3Dノードの基本を押さえることです。まずはこのノードが何をしてくれるのかを確認してみましょう。
AudioStreamPlayer3D は、3D空間内で位置情報を持つ音声再生ノードです。リスナー(通常はCamera3D)との距離と方向に応じて音量とパンニングが自動的に変化します。
主要プロパティ
まずは基本となるプロパティを理解しましょう。これらの設定で、音がどこまで聞こえるか、どのように減衰するかをコントロールできます。
| プロパティ | 説明 | デフォルト値 |
|---|---|---|
max_distance | 音が聞こえる最大距離 | 0(無制限) |
unit_size | 音量が半分になる距離 | 10.0 |
attenuation_model | 距離による音量減衰の計算方式 | InverseDistance |
max_polyphony | 同時再生可能な音の数 | 1 |
panning_strength | ステレオパンニングの強さ | 1.0 |
emission_angle_enabled | 指向性の有効化 | false |
emission_angle_degrees | 音が届く角度の範囲 | 45.0 |
基本的なセットアップ
敵キャラクターに足音を持たせる例で、基本的な設定の流れを見てみましょう。
# シーンツリー例
# Enemy (CharacterBody3D)
# └── FootstepSound (AudioStreamPlayer3D)
# 敵の足音を設定
@onready var footstep = $FootstepSound
func _ready():
footstep.stream = preload("res://audio/sfx/footstep.ogg")
footstep.max_distance = 30.0 # 30m先まで聞こえる
footstep.unit_size = 5.0 # 5mで音量半減
footstep.bus = "SFX"
func play_footstep():
if not footstep.playing:
footstep.play()
指向性サウンド
たとえば監視カメラの警告音やスピーカーの放送など、特定方向にのみ音を飛ばしたい場面があります。その場合は emission_angle_enabled = true にして emission_angle_degrees で角度範囲を設定します。emission_angle_filter_attenuation_db で範囲外の減衰量を指定します。
減衰モデルの選択
AudioStreamPlayer3Dの基本がわかったところで、次は音の「聞こえ方」を決める減衰モデルを選んでみましょう。距離に応じた音量の減衰方式を選択できます。リアルな物理法則に従うか、ゲームプレイを優先するかで最適なモデルは変わります。
| モデル | 減衰の特徴 | 適したシーン |
|---|---|---|
| Inverse Distance | 距離に反比例して減衰(緩やか) | 屋外の広いフィールド |
| Inverse Square Distance | 距離の2乗に反比例(現実的) | リアル志向のゲーム全般 |
| Logarithmic | 対数的に減衰(人間の聴覚に近い) | 室内、近距離のインタラクション |
| Disabled | 距離による減衰なし | 環境音、アンビエント |
設定方法
以下のコードで減衰モデルと距離パラメータを設定します。コメントにシーン規模ごとの目安を載せているので、自分のゲームに合わせて調整してみてください。
# 減衰モデルの設定
footstep.attenuation_model = AudioStreamPlayer3D.ATTENUATION_INVERSE_SQUARE_DISTANCE
# unit_sizeとmax_distanceの目安
# 小さい部屋: unit_size=2.0, max_distance=10.0
# 中規模の屋内: unit_size=5.0, max_distance=25.0
# 屋外フィールド: unit_size=10.0, max_distance=50.0
tips:
unit_sizeは「音量が半分になる距離」です。値を大きくすると遠くまで聞こえ、小さくすると近くでしか聞こ えません。
AudioListener3Dの活用
音源の設定ができたら、次は「どこで音を聴くか」を考えましょう。TPSのように俯瞰カメラを使うゲームでは、カメラ位置とプレイヤー位置がずれるため、音の聞こえ方に違和感が出ることがあります。
デフォルトでは、current = true の Camera3D がリスナーとして機能します。しかし、カメラとリスナーを分離したい場合は AudioListener3D を使います。
Camera3Dとの使い分け
| パターン | リスナー | 用途 |
|---|---|---|
| 一般的なゲーム | Camera3D(デフォルト) | カメラ位置=聴取位置で問題ない場合 |
| TPS(三人称) | AudioListener3D | カメラが引きでもプレイヤー付近の音を聞かせたい |
| カットシーン | AudioListener3D | カメラが動いてもプレイヤー位置の音を維持 |
| VR | AudioListener3D | ヘッドトラッキングと連動 |
実装例
プレイヤーの子ノードにAudioListener3Dを配置して有効化するだけで、カメラがどこにあってもプレイヤー位置基準で音が聞こえるようになります。
# Player (CharacterBody3D) の子ノードにAudioListener3Dを追加
@onready var listener = $AudioListener3D
func _ready():
listener.make_current() # このリスナーを有効化
ドップラー効果
ここからはさらにリアルな音響表現に踏み込みます。移動する音源の音程が変化するドップラー効果を有効にしてみましょう。レースゲームで他の車が追い抜いていくシーンや、救急車が通り過ぎるときの音程変化を再現できます。
設定手順
# 1. AudioStreamPlayer3Dのドップラートラッキングを有効化
$AudioStreamPlayer3D.doppler_tracking = AudioStreamPlayer3D.DOPPLER_TRACKING_PHYSICS_STEP
# トラッキングモードの選択
# DOPPLER_TRACKING_DISABLED … 無効(デフォルト)
# DOPPLER_TRACKING_IDLE_STEP … _process()に同期
# DOPPLER_TRACKING_PHYSICS_STEP … _physics_process()に同期(推奨)
プロジェクト設定の Audio > General > Doppler Tracking を有効にし、Default Doppler Factor で効果の強さを調整します(デフォルト: 1.0)。
tips:
PHYSICS_STEPを使うと物理演算と同期するため、高速移動するオブジェクトでも安定したドップラー効果が得られます。
エリアリバーブゾーン
音源とリスナーの設定ができたところで、もう一歩進んで空間ごとの音響演出を追加してみましょう。RPGで洞窟に足を踏み入れた瞬間、音に残響がかかって雰囲気が一変する――そんな体験を Area3D で実現できます。特定の空間に入ったときだけリバーブを適用する仕組みです。
セットアップ
Area3D に CollisionShape3D でリバーブ範囲を設定し、Reverb Bus プロパティで専用バスを指定します。以下のコードでは、洞窟用のリバーブゾーンをスクリプトから構成しています。
func setup_reverb_zone():
var area = $ReverbZone as Area3D
area.audio_bus_override = true
area.audio_bus_name = &"CaveReverb"
area.reverb_bus_enabled = true
area.reverb_bus_name = &"CaveReverb"
area.reverb_bus_amount = 0.6
area.reverb_bus_uniformity = 0.8
CaveReverb バスには AudioEffectReverb(room_size: 0.85, damping: 0.3, wet: 0.4)を追加しておきます。プレイヤーが Area3D に入ると、範囲内の音声出力が自動的にこのバスに切り替わります。
動的制御とパフォーマンス
ここまでの設定で基本的な3D音響は完成です。最後に、より自然な聞こえ方を実現するフィルタ制御と、実際のゲームで避けられないパフォーマンス対策を見ていきましょう。
距離ベースのフィルタ制御
遠くの音は壁や空気によって高音が減衰し、こもって聞こえます。この効果をローパスフィルタで再現すると、距離感がぐっとリアルになります。以下のスクリプトをAudioStreamPlayer3Dにアタッチして使います。
extends AudioStreamPlayer3D
@export var listener_node: Node3D
@export var far_distance: float = 30.0
func _process(_delta):
if not listener_node:
return
var distance = global_position.distance_to(listener_node.global_position)
var ratio = clampf(distance / far_distance, 0.0, 1.0)
# 遠い音はこもる
attenuation_filter_cutoff_hz = lerpf(20500.0, 2000.0, ratio)
attenuation_filter_db = lerpf(0.0, -10.0, ratio)
パフォーマンス最適化
オープンワールドのように大量の音源が存在するシーンでは、CPU負荷が問題になりがちです。以下の最適化テクニックを活用しましょう。
| 対策 | 説明 |
|---|---|
| max_distanceの設定 | 0(無制限)を避け、必要な範囲のみに制限 |
| max_polyphonyの制限 | 同時再生数を1〜4に抑える |
| 同時再生ノード数の管理 | 20〜30以下を目安に |
| LOD的な管理 | 遠距離の音源は playing = false で停止 |
リスナーからの距離に応じて音源を自動停止するスクリプトの例です。画面外の音を再生し続ける無駄を省けます。
# 遠距離の音源を自動停止してCPU負荷を軽減
func _process(_delta):
var camera = get_viewport().get_camera_3d()
if not camera:
return
var distance = global_position.distance_to(camera.global_position)
if distance > max_distance * 1.2 and playing:
stop()
elif distance <= max_distance and not playing:
play()
まとめ
- AudioStreamPlayer3D はリスナーとの距離・方向に応じて音量とパンニングが自動変化する
- 減衰モデル はシーンの規模に合わせて選択し、
unit_sizeとmax_distanceを適切に設定する - AudioListener3D を使うとカメラとリスナーの位置を分離でき、TPSやカットシーンに有効
- ドップラー効果 は
PHYSICS_STEPトラッキングで物理演算と同期させるのが安定 - Area3Dのリバーブゾーン で空間ごとに異なる音響環境を作れる
- パフォーマンスには max_distance設定 と 同時再生数の制限 が重要