金属度与粗糙度——PBR 直觉
第 21 章的材质墙只用了十五颗球,横轴粗糙度三档、纵轴金属感五档。这次我们拉满:五五二十五颗,粗糙度从 0.05 到 1.0、金属感从 0.0 到 1.0,每个交叉点一颗:
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>>,
) {
let sphere = meshes.add(Sphere::new(0.4).mesh().uv(32, 18));
let roughness_values = [0.05, 0.25, 0.5, 0.75, 1.0];
let metallic_values = [0.0, 0.25, 0.5, 0.75, 1.0];
for (row, &metallic) in metallic_values.iter().enumerate() {
for (col, &roughness) in roughness_values.iter().enumerate() {
let x = (col as f32 - 2.0) * 1.2;
let z = (row as f32 - 2.0) * 1.2;
commands.spawn((
Mesh3d(sphere.clone()),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgb(0.8, 0.2, 0.1),
metallic,
perceptual_roughness: roughness,
..default()
})),
Transform::from_xyz(x, 0.4, z),
));
}
}
commands.spawn((
Mesh3d(meshes.add(Plane3d::default().mesh().size(8.0, 8.0))),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgb(0.15, 0.15, 0.15),
perceptual_roughness: 1.0,
..default()
})),
));
commands.spawn((
DirectionalLight {
illuminance: light_consts::lux::FULL_DAYLIGHT,
contact_shadows_enabled: true,
..default()
},
Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -0.8, 0.4, 0.0)),
));
commands.spawn((
Camera3d::default(),
Transform::from_xyz(4.0, 4.5, 6.0).looking_at(Vec3::new(0.0, 0.2, 0.0), Vec3::Y),
));
}Listing 24-1:五乘五材质墙——粗糙度与金属感的完整交叉(examples/listing-24-01.rs)
cargo run -p ch24-pbr-materials --example listing-24-01读图同第 21 章的方法:从右下角(非金属、最糙)往左上角(金属、最光滑)读。右下角是粉笔——均匀的哑光、没有高光;左下角是上了亮光漆的瓷——白色高光锐利地钉在球面上;右上角是磨砂铜——暖金色铺满;左上角是镜面金属——在没有环境贴图的世界里,它忠实地反射虚空,所以最暗。
二十五颗球比十五颗多出的,是对中间地带的覆盖:metallic = 0.5 的那一行尤其值得看。它既不完全是"非金属的白高光",也不完全是"金属的有色反射",而是两者的混合——现实里"锈蚀的金属""沾了灰的铝"就是这个区域。metallic 的设计意图就是让 0 和 1 做分界,中间值留给"混合表面"这类特殊情况。
粗糙度的刻度
perceptual_roughness 的 0.089 下限在着色器里钳制,写 0.0 也等同于 0.089——这是浮点精度的护栏,不是能省就省的"光滑无限大"。0.5 是 Blender 默认值,视觉上恰好是"半糙"——不高不低,适合做初始调参的锚点。1.0 则是彻底的漫反射面,高光完全消失。
一个常见误解:粗糙度越高,画面越"暗"。不是——粗糙度只是把高光摊散了,总能量不变。哑光白纸(roughness = 1.0)依然白,只是没有那粒亮斑。真正影响明暗的是金属感——金属没有漫反射,一旦粗糙度低到接近镜面,它反射的只有环境。
从"看"到"用"
在实际项目里,二十五种组合不会同时出现,但调参的路径是一样的:先定 metallic(这东西是金属还是非金属?),再调 perceptual_roughness(想要多光滑?),最后微调 base_color。这三步的顺序不能反——如果先选了漂亮的金色、再把 metallic 从 0 拉到 1,金色会变暗变脏,因为金属的固有色只作用于反射、不作用于漫反射。