8. 音效与视觉效果
2026/4/14大约 4 分钟
音效与视觉效果
飞行模拟器的音效和视觉效果追求的是真实感而非炫酷感。发动机声音随油门细腻变化、雨点打在风挡上的声音、起落架收放的机械声——这些细节才是让玩家觉得"我真的在飞"的关键。
本章你将学到
- 发动机音效:螺旋桨和涡扇发动机的不同音效
- 环境音效:风声、雨声、驾驶舱内部音
- 视觉特效:发动机尾焰、螺旋桨模糊、雨雪效果
- 昼夜系统:随时间变化的光照和天色
- 逼真天空:云、大气散射
发动机音效设计
不同类型发动机有截然不同的声音特征:
| 发动机类型 | 声音特征 | 代表飞机 |
|---|---|---|
| 螺旋桨(活塞) | 低沉的"哒哒哒"声,随转速变化 | 塞斯纳172 |
| 涡桨 | 螺旋桨+喷气声混合 | ATR 72 |
| 涡扇(小推力) | 高频喷气声 | 支线客机 |
| 涡扇(大推力) | 深沉轰鸣,起飞时震耳欲聋 | 波音737/777 |
GDScript
extends AudioStreamPlayer3D
## 螺旋桨发动机音效控制器
class_name PropellerEngineAudio
## 分层音效:低频(发动机)+ 高频(螺旋桨切风声)
@export var engine_low_stream: AudioStream ## 低频发动机嗡鸣
@export var engine_high_stream: AudioStream ## 高频螺旋桨声
@onready var aircraft: RealisticFlightController = get_parent()
@onready var high_freq_player: AudioStreamPlayer3D = $HighFreqPlayer
func _process(_delta: float) -> void:
var throttle := aircraft.throttle
var rpm_ratio := throttle ## 简化:直接用油门代表转速比
## 低频:音调随转速变化(慢车vs全油门差异明显)
pitch_scale = lerp(0.5, 1.0, rpm_ratio)
volume_db = lerp(-20.0, -3.0, rpm_ratio)
## 高频:螺旋桨切风声在高转速时更明显
high_freq_player.pitch_scale = lerp(0.8, 1.5, rpm_ratio)
high_freq_player.volume_db = lerp(-30.0, -10.0, rpm_ratio)C
using Godot;
public partial class PropellerEngineAudio : AudioStreamPlayer3D
{
[Export] public AudioStream EngineLowStream;
[Export] public AudioStreamHighStream;
private RealisticFlightController _aircraft;
private AudioStreamPlayer3D _highFreqPlayer;
public override void _Ready()
{
_aircraft = GetParent<RealisticFlightController>();
_highFreqPlayer = GetNode<AudioStreamPlayer3D>("HighFreqPlayer");
}
public override void _Process(double delta)
{
float throttle = _aircraft.Throttle;
PitchScale = Mathf.Lerp(0.5f, 1f, throttle);
VolumeDb = Mathf.Lerp(-20f, -3f, throttle);
_highFreqPlayer.PitchScale = Mathf.Lerp(0.8f, 1.5f, throttle);
_highFreqPlayer.VolumeDb = Mathf.Lerp(-30f, -10f, throttle);
}
}驾驶舱内部音效
驾驶舱里有很多细节音效,让玩家感觉身临其境:
| 音效 | 触发条件 | 说明 |
|---|---|---|
| 风挡风声 | 速度越快越响 | 低沉的气流噪音 |
| 起落架收放 | 操作起落架时 | 机械声+液压声 |
| 襟翼操作 | 操作襟翼时 | 电机声+风切声 |
| 刹车 | 踩刹车时 | 摩擦噪音 |
| 失速警报 | 迎角过大时 | "叮叮叮"警报声 |
| 地面接近警报 | 下降率过大+低高度 | "拉起!拉起!" |
| 超速警报 | 超过红线速度 | 连续警报声 |
昼夜与天空系统
DirectionalLight3D 模拟太阳
GDScript
extends DirectionalLight3D
## 昼夜系统 - 模拟太阳的位置变化
class_name DayNightSystem
@export var day_duration: float = 600.0 ## 一天的时长(秒),默认10分钟
@export var start_hour: float = 8.0 ## 游戏开始时的小时数(8=早8点)
var current_time: float = 0.0 ## 从游戏开始的秒数
func _process(delta: float) -> void:
current_time += delta
_update_sun_position()
_update_sky_color()
func _update_sun_position() -> void:
## 把游戏时间映射到太阳位置(0°=午夜,180°=正午)
var game_hour := (start_hour + current_time / day_duration * 24.0)
var sun_angle := (game_hour / 24.0) * 360.0 - 90.0 ## 减90使正午在头顶
rotation_degrees = Vector3(sun_angle, 0, 0)
## 夜间关闭阳光
visible = sin(deg_to_rad(sun_angle)) > -0.1
func _update_sky_color() -> void:
## 根据太阳高度角调整环境光颜色
var sun_elevation := sin(deg_to_rad(rotation_degrees.x))
if sun_elevation < 0:
light_color = Color(0.0, 0.0, 0.1) ## 夜晚:深蓝
elif sun_elevation < 0.2:
light_color = Color(1.0, 0.5, 0.2) ## 日出/日落:橙色
else:
light_color = Color(1.0, 1.0, 0.95) ## 白天:暖白C
using Godot;
public partial class DayNightSystem : DirectionalLight3D
{
[Export] public float DayDuration = 600f;
[Export] public float StartHour = 8f;
private float _currentTime = 0f;
public override void _Process(double delta)
{
_currentTime += (float)delta;
UpdateSunPosition();
}
private void UpdateSunPosition()
{
float gameHour = StartHour + _currentTime / DayDuration * 24f;
float sunAngle = gameHour / 24f * 360f - 90f;
RotationDegrees = new Vector3(sunAngle, 0, 0);
Visible = Mathf.Sin(Mathf.DegToRad(sunAngle)) > -0.1f;
float elevation = Mathf.Sin(Mathf.DegToRad(RotationDegrees.X));
if (elevation < 0)
LightColor = new Color(0f, 0f, 0.1f);
else if (elevation < 0.2f)
LightColor = new Color(1f, 0.5f, 0.2f);
else
LightColor = new Color(1f, 1f, 0.95f);
}
}螺旋桨模糊效果
高速旋转的螺旋桨看起来是半透明圆盘,而不是单独的桨叶:
- 低转速(慢车):能看清桨叶,转速较慢
- 中转速:桨叶开始模糊
- 高转速(全油门):完全变成半透明圆盘
在 Godot 中,可以用两个网格切换实现:
- 低速:显示真实桨叶模型,用
AnimationPlayer旋转 - 高速:隐藏桨叶,显示半透明圆盘
MeshInstance3D,切换阈值约 500 RPM
下一步
音效和视觉完成后,最后进行 打磨与发布。
