Skip to content

SpotLight:聚光灯

聚光灯从一点向特定方向发光,光线被限制在两个锥角之内。舞台追光、手电筒、车灯是现实中的对应物。

最小配置

rust
use std::f32::consts::PI;

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(Cuboid::new(0.8, 0.8, 0.8))),
        MeshMaterial3d(materials.add(StandardMaterial {
            base_color: Color::srgb(0.1, 0.5, 0.8),
            perceptual_roughness: 0.5,
            ..default()
        })),
        Transform::from_xyz(-1.0, 0.4, 0.0),
    ));
    commands.spawn((
        Mesh3d(meshes.add(Sphere::new(0.5).mesh().uv(32, 18))),
        MeshMaterial3d(materials.add(StandardMaterial {
            base_color: Color::srgb(0.8, 0.2, 0.2),
            metallic: 0.6,
            perceptual_roughness: 0.4,
            ..default()
        })),
        Transform::from_xyz(1.0, 0.5, 0.0),
    ));

    // 聚光灯:从天花板照向地面某点
    commands.spawn((
        SpotLight {
            intensity: 80_000.0,
            color: Color::srgb(1.0, 0.95, 0.8),
            inner_angle: PI / 8.0,   // 内锥角 22.5°
            outer_angle: PI / 4.0,   // 外锥角 45°
            contact_shadows_enabled: true,
            range: 10.0,
            radius: 0.2,
            ..default()
        },
        Transform::from_xyz(0.0, 4.0, 0.0)
            .looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y),
        children![(
            Mesh3d(meshes.add(Capsule3d::new(0.06, 0.15))),
            MeshMaterial3d(materials.add(StandardMaterial {
                base_color: Color::srgb(10.0, 9.5, 8.0),
                emissive: LinearRgba::new(3.0, 2.8, 2.0, 0.0),
                ..default()
            })),
            Transform::from_rotation(Quat::from_rotation_x(PI / 2.0)),
        )],
    ));

    // 相机
    commands.spawn((
        Camera3d::default(),
        Transform::from_xyz(4.0, 3.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
    ));
}

Listing 22-3:SpotLight——锥角与方向

锥角:inner_angle 与 outer_angle

两个角度定义了光照锥形区域:

参数含义
inner_angle内锥角,此范围内的光照强度保持不变
outer_angle外锥角,光强从内锥边界衰减至外锥边界降为零

两角差距越大,光照边缘越柔和。差距为零产生锐利边界。角度看值如下计算:

rust
// 一个聚光灯的合理取值:
SpotLight {
    inner_angle: PI / 8.0,   // 22.5°
    outer_angle: PI / 4.0,   // 45°
    ..
}

方向控制

与点光源一样,位置决定发光原点。方向由 Transform::looking_at 设置——聚光灯沿实体的 forward(-Z)方向发光:

rust
Transform::from_xyz(0.0, 4.0, 0.0)
    .looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y),

与其他光源的对比

特性DirectionalLightPointLightSpotLight
位置有无意义
方向控制Transform 旋转无(全方向)Transform 旋转
衰减平方反比平方反比 + 锥角衰减
典型用途太阳/月光灯泡/烛光手电/车灯/追光