透明与 Alpha 模式
alpha_mode 字段控制材质的透明行为。Bevy 提供六种模式:
| 模式 | 行为 |
|---|---|
AlphaMode::Opaque(默认) | 忽略 alpha,完全不透明 |
AlphaMode::Mask(threshold) | alpha < threshold 则丢弃,否则当不透明 |
AlphaMode::Blend | 标准 alpha 混合 |
AlphaMode::Premultiplied | 预乘 alpha 混合 |
AlphaMode::Add | 加法混合 |
AlphaMode::Multiply | 乘法混合 |
下面是三种最常用模式的并排对比:
rust
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, rotate_camera)
.run();
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let panel = meshes.add(Cuboid::new(2.0, 2.0, 0.05));
let background = meshes.add(Cuboid::new(1.0, 1.0, 1.0));
commands.spawn((
Mesh3d(background.clone()),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgb(0.2, 0.5, 0.8),
perceptual_roughness: 0.3,
..default()
})),
Transform::from_xyz(0.0, 0.5, -1.5),
));
// Opaque
commands.spawn((
Mesh3d(panel.clone()),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgba(0.8, 0.2, 0.2, 1.0),
alpha_mode: AlphaMode::Opaque,
..default()
})),
Transform::from_xyz(-2.5, 1.0, 0.0),
));
// Mask
commands.spawn((
Mesh3d(panel.clone()),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgba(0.2, 0.8, 0.2, 0.5),
alpha_mode: AlphaMode::Mask(0.5),
..default()
})),
Transform::from_xyz(0.0, 1.0, 0.0),
));
// Blend
commands.spawn((
Mesh3d(panel.clone()),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgba(0.2, 0.2, 0.8, 0.5),
alpha_mode: AlphaMode::Blend,
..default()
})),
Transform::from_xyz(2.5, 1.0, 0.0),
));
// Ground
commands.spawn((
Mesh3d(meshes.add(Plane3d::default().mesh().size(12.0, 12.0))),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgb(0.3, 0.3, 0.3),
perceptual_roughness: 1.0,
..default()
})),
));
// Light
commands.spawn((
DirectionalLight {
illuminance: light_consts::lux::FULL_DAYLIGHT,
contact_shadows_enabled: true,
..default()
},
Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -0.6, 0.3, 0.0)),
));
// Camera
commands.spawn((
Camera3d::default(),
Transform::from_xyz(0.0, 3.0, 7.0).looking_at(Vec3::new(0.0, 0.8, 0.0), Vec3::Y),
));
}
fn rotate_camera(time: Res<Time>, mut query: Query<&mut Transform, With<Camera3d>>) {
for mut transform in &mut query {
let angle = time.elapsed_secs() * 0.3;
let radius = 7.0;
transform.translation.x = angle.sin() * radius;
transform.translation.z = angle.cos() * radius;
transform.translation.y = 3.0;
*transform = transform.looking_at(Vec3::new(0.0, 0.8, 0.0), Vec3::Y);
}
}Listing 24-1:三块面板——Opaque、Mask、Blend 从左到右(examples/listing-24-04.rs)
console
cargo run -p ch24-pbr-materials --example listing-24-04相机在绕圈,方便你从不同角度观察三块面板的行为差异。
Opaque vs Mask vs Blend
- Opaque:最高效。着色器可以跳过所有透明计算,深度缓冲直接写入。绝大多数不透明物体用这个。
- Mask(0.5):alpha ≥ 0.5 的像素完全不透明,< 0.5 的完全丢弃。没有半透明,所以也没有排序问题。适合树叶、铁丝网、像素风特效——边缘是硬切的。
- Blend:真正的半透明。alpha 值被用于线性插值前景和背景。代价是需要排序(Bevy 按从后到前渲染 blend 物体),且不写深度缓冲。适合玻璃、烟雾、幽灵。
Mask 和 Blend 的选择取决于"边缘应该硬还是软"。树叶的锯齿边缘用 Mask(阈值 0.5),磨砂玻璃的渐变用 Blend。
Add 和 Multiply
- Add:颜色相加,越叠越亮。黑色不产生效果。适合全息、激光、能量场。
- Multiply:颜色相乘,越叠越暗。白色不产生效果。适合彩色玻璃、窗膜、有色液体。
排序陷阱
Blend 物体的渲染顺序很重要:Bevy 按物体的 Z 距离从后到前排序,但这是物体级别的排序,不是像素级别。多个半透明物体互相重叠时,可能出现排序错误(A 在 B 前面但画在了后面)。缓解方法:
- 减少半透明物体的数量和重叠
- 用 Mask 代替 Blend(如果硬边缘可接受)
- 对粒子等大量半透明物体,用 Add 模式(不需要排序)