bevy/crates/bevy_pbr/src/render/pbr_bindings.wgsl
Patrick Walton 1c765c9ae7
Add support for specular tints and maps per the KHR_materials_specular glTF extension. (#14069)
This commit allows specular highlights to be tinted with a color and for
the reflectance and color tint values to vary across a model via a pair
of maps. The implementation follows the [`KHR_materials_specular`] glTF
extension. In order to reduce the number of samplers and textures in the
default `StandardMaterial` configuration, the maps are gated behind the
`pbr_specular_textures` Cargo feature.

Specular tinting is currently unsupported in the deferred renderer,
because I didn't want to bloat the deferred G-buffers. A possible fix
for this in the future would be to make the G-buffer layout more
configurable, so that specular tints could be supported on an opt-in
basis. As an alternative, Bevy could force meshes with specular tints to
render in forward mode. Both of these solutions require some more
design, so I consider them out of scope for now.

Note that the map is a *specular* map, not a *reflectance* map. In Bevy
and Filament terms, the reflectance values in the specular map range
from [0.0, 0.5], rather than [0.0, 1.0]. This is an unfortunate
[`KHR_materials_specular`] specification requirement that stems from the
fact that glTF is specified in terms of a specular strength model, not
the reflectance model that Filament and Bevy use. A workaround, which is
noted in the `StandardMaterial` documentation, is to set the
`reflectance` value to 2.0, which spreads the specular map range from
[0.0, 1.0] as normal.

The glTF loader has been updated to parse the [`KHR_materials_specular`]
extension. Note that, unless the non-default `pbr_specular_textures` is
supplied, the maps are ignored. The `specularFactor` value is applied as
usual. Note that, as with the specular map, the glTF `specularFactor` is
twice Bevy's `reflectance` value.

This PR adds a new example, `specular_tint`, which demonstrates the
specular tint and map features. Note that this example requires the
[`KHR_materials_specular`] Cargo feature.

[`KHR_materials_specular`]:
https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_specular

## Changelog

### Added

* Specular highlights can now be tinted with the `specular_tint` field
in `StandardMaterial`.
* Specular maps are now available in `StandardMaterial`, gated behind
the `pbr_specular_textures` Cargo feature.
* The `KHR_materials_specular` glTF extension is now supported, allowing
for customization of specular reflectance and specular maps. Note that
the latter are gated behind the `pbr_specular_textures` Cargo feature.
2025-01-26 20:38:46 +00:00

94 lines
5.1 KiB
WebGPU Shading Language

#define_import_path bevy_pbr::pbr_bindings
#import bevy_pbr::pbr_types::StandardMaterial
#ifdef BINDLESS
@group(2) @binding(0) var<storage> material: binding_array<StandardMaterial, 16>;
@group(2) @binding(1) var base_color_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(2) var base_color_sampler: binding_array<sampler, 16>;
@group(2) @binding(3) var emissive_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(4) var emissive_sampler: binding_array<sampler, 16>;
@group(2) @binding(5) var metallic_roughness_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(6) var metallic_roughness_sampler: binding_array<sampler, 16>;
@group(2) @binding(7) var occlusion_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(8) var occlusion_sampler: binding_array<sampler, 16>;
@group(2) @binding(9) var normal_map_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(10) var normal_map_sampler: binding_array<sampler, 16>;
@group(2) @binding(11) var depth_map_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(12) var depth_map_sampler: binding_array<sampler, 16>;
#else // BINDLESS
@group(2) @binding(0) var<uniform> material: StandardMaterial;
@group(2) @binding(1) var base_color_texture: texture_2d<f32>;
@group(2) @binding(2) var base_color_sampler: sampler;
@group(2) @binding(3) var emissive_texture: texture_2d<f32>;
@group(2) @binding(4) var emissive_sampler: sampler;
@group(2) @binding(5) var metallic_roughness_texture: texture_2d<f32>;
@group(2) @binding(6) var metallic_roughness_sampler: sampler;
@group(2) @binding(7) var occlusion_texture: texture_2d<f32>;
@group(2) @binding(8) var occlusion_sampler: sampler;
@group(2) @binding(9) var normal_map_texture: texture_2d<f32>;
@group(2) @binding(10) var normal_map_sampler: sampler;
@group(2) @binding(11) var depth_map_texture: texture_2d<f32>;
@group(2) @binding(12) var depth_map_sampler: sampler;
#endif // BINDLESS
#ifdef PBR_ANISOTROPY_TEXTURE_SUPPORTED
#ifdef BINDLESS
@group(2) @binding(13) var anisotropy_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(14) var anisotropy_sampler: binding_array<sampler, 16>;
#else // BINDLESS
@group(2) @binding(13) var anisotropy_texture: texture_2d<f32>;
@group(2) @binding(14) var anisotropy_sampler: sampler;
#endif // BINDLESS
#endif // PBR_ANISOTROPY_TEXTURE_SUPPORTED
#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED
#ifdef BINDLESS
@group(2) @binding(15) var specular_transmission_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(16) var specular_transmission_sampler: binding_array<sampler, 16>;
@group(2) @binding(17) var thickness_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(18) var thickness_sampler: binding_array<sampler, 16>;
@group(2) @binding(19) var diffuse_transmission_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(20) var diffuse_transmission_sampler: binding_array<sampler, 16>;
#else // BINDLESS
@group(2) @binding(15) var specular_transmission_texture: texture_2d<f32>;
@group(2) @binding(16) var specular_transmission_sampler: sampler;
@group(2) @binding(17) var thickness_texture: texture_2d<f32>;
@group(2) @binding(18) var thickness_sampler: sampler;
@group(2) @binding(19) var diffuse_transmission_texture: texture_2d<f32>;
@group(2) @binding(20) var diffuse_transmission_sampler: sampler;
#endif // BINDLESS
#endif // PBR_TRANSMISSION_TEXTURES_SUPPORTED
#ifdef PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
#ifdef BINDLESS
@group(2) @binding(21) var clearcoat_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(22) var clearcoat_sampler: binding_array<sampler, 16>;
@group(2) @binding(23) var clearcoat_roughness_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(24) var clearcoat_roughness_sampler: binding_array<sampler, 16>;
@group(2) @binding(25) var clearcoat_normal_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(26) var clearcoat_normal_sampler: binding_array<sampler, 16>;
#else // BINDLESS
@group(2) @binding(21) var clearcoat_texture: texture_2d<f32>;
@group(2) @binding(22) var clearcoat_sampler: sampler;
@group(2) @binding(23) var clearcoat_roughness_texture: texture_2d<f32>;
@group(2) @binding(24) var clearcoat_roughness_sampler: sampler;
@group(2) @binding(25) var clearcoat_normal_texture: texture_2d<f32>;
@group(2) @binding(26) var clearcoat_normal_sampler: sampler;
#endif // BINDLESS
#endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
#ifdef PBR_SPECULAR_TEXTURES_SUPPORTED
#ifdef BINDLESS
@group(2) @binding(27) var specular_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(28) var specular_sampler: binding_array<sampler, 16>;
@group(2) @binding(29) var specular_tint_texture: binding_array<texture_2d<f32>, 16>;
@group(2) @binding(30) var specular_tint_sampler: binding_array<sampler, 16>;
#else
@group(2) @binding(27) var specular_texture: texture_2d<f32>;
@group(2) @binding(28) var specular_sampler: sampler;
@group(2) @binding(29) var specular_tint_texture: texture_2d<f32>;
@group(2) @binding(30) var specular_tint_sampler: sampler;
#endif // BINDLESS
#endif // PBR_SPECULAR_TEXTURES_SUPPORTED