PointLight:点光源
点光源从一个点向所有方向发光。蜡烛、灯泡、篝火都是现实中的例子。与平行光不同,点光源有位置和衰减范围。
最小配置
rust
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
// 地面
commands.spawn((
Mesh3d(meshes.add(Plane3d::default().mesh().size(8.0, 8.0))),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgb(0.3, 0.3, 0.3),
perceptual_roughness: 1.0,
..default()
})),
));
// 一个金属球来展示点光源的高光和衰减
commands.spawn((
Mesh3d(meshes.add(Sphere::new(0.8).mesh().uv(32, 18))),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgb(0.9, 0.2, 0.2),
metallic: 0.9,
perceptual_roughness: 0.3,
..default()
})),
Transform::from_xyz(0.0, 0.8, 0.0),
));
// 点光源:挂在球体正上方,加一盏小灯球做视觉提示
commands.spawn((
PointLight {
intensity: 50_000.0, // 流明
range: 6.0,
radius: 0.1,
contact_shadows_enabled: true,
..default()
},
Transform::from_xyz(0.0, 3.0, 0.0),
children![(
Mesh3d(meshes.add(Sphere::new(0.08).mesh().uv(8, 8))),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgb(10.0, 10.0, 10.0),
emissive: LinearRgba::new(5.0, 5.0, 5.0, 0.0),
..default()
})),
)],
));
// 相机
commands.spawn((
Camera3d::default(),
Transform::from_xyz(4.0, 2.5, 5.0).looking_at(Vec3::new(0.0, 0.8, 0.0), Vec3::Y),
));
}Listing 22-2:点光源——强度、范围与衰减半径
四个关键参数
| 参数 | 含义 | 默认值 | 影响 |
|---|---|---|---|
intensity | 光通量,流明(lm) | 相当于大型影院灯 | 决定了亮度峰值 |
range | 光照最远距离(米) | 20.0 | 超出此范围完全无光 |
radius | 光源半径(米) | 0.0 | 影响高光大小和软阴影半影 |
contact_shadows_enabled | 是否投阴影 | false | 启用后性能开销显著 |
intensity 的建议取值为 light_consts::lumens 模块中的参考值:
| 值 | 流明 | 对应实物 |
|---|---|---|
LUMEN_FAMILY_ROOM | 50 | 客厅灯 |
LUMEN_OFFICE | 320—500 | 办公室照明 |
VERY_LARGE_CINEMA_LIGHT | 100,000 | 大型影院灯 |
范围与衰减
range 不是硬截止——Bevy 在 range 内使用物理正确的平方反比衰减,超出后完全截断。因此 range 应与 intensity 配合调整:高强度配大范围,避免截断处出现视觉硬边。
小灯球技巧
在点光源实体下加一个子实体做发光球体,是一种常见的视觉提示手法。子实体用 emissive(自发光)材质表现灯体自身发光:
rust
children![(
Mesh3d(meshes.add(Sphere::new(0.08).mesh().uv(8, 8))),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgb(10.0, 10.0, 10.0),
emissive: LinearRgba::new(5.0, 5.0, 5.0, 0.0),
..default()
})),
)]