mirror of
https://github.com/bevyengine/bevy
synced 2024-12-18 17:13:10 +00:00
Make StandardMaterial
bindless. (#16644)
This commit makes `StandardMaterial` use bindless textures, as implemented in PR #16368. Non-bindless mode, as used for example in Metal and WebGL 2, remains fully supported via a plethora of `#ifdef BINDLESS` preprocessor definitions. Unfortunately, this PR introduces quite a bit of unsightliness into the PBR shaders. This is a result of the fact that WGSL supports neither passing binding arrays to functions nor passing individual *elements* of binding arrays to functions, except directly to texture sample functions. Thus we're unable to use the `sample_texture` abstraction that helped abstract over the meshlet and non-meshlet paths. I don't think there's anything we can do to help this other than to suggest improvements to upstream Naga.
This commit is contained in:
parent
7236070573
commit
7ed1f327d9
14 changed files with 574 additions and 166 deletions
|
@ -155,14 +155,32 @@ impl<B: Material, E: MaterialExtension> AsBindGroup for ExtendedMaterial<B, E> {
|
|||
layout: &BindGroupLayout,
|
||||
render_device: &RenderDevice,
|
||||
(base_param, extended_param): &mut SystemParamItem<'_, '_, Self::Param>,
|
||||
mut force_no_bindless: bool,
|
||||
) -> Result<UnpreparedBindGroup<Self::Data>, AsBindGroupError> {
|
||||
// Only allow bindless mode if both the base material and the extension
|
||||
// support it.
|
||||
force_no_bindless = force_no_bindless
|
||||
|| B::BINDLESS_SLOT_COUNT.is_none()
|
||||
|| E::BINDLESS_SLOT_COUNT.is_none();
|
||||
|
||||
// add together the bindings of the base material and the user material
|
||||
let UnpreparedBindGroup {
|
||||
mut bindings,
|
||||
data: base_data,
|
||||
} = B::unprepared_bind_group(&self.base, layout, render_device, base_param)?;
|
||||
let extended_bindgroup =
|
||||
E::unprepared_bind_group(&self.extension, layout, render_device, extended_param)?;
|
||||
} = B::unprepared_bind_group(
|
||||
&self.base,
|
||||
layout,
|
||||
render_device,
|
||||
base_param,
|
||||
force_no_bindless,
|
||||
)?;
|
||||
let extended_bindgroup = E::unprepared_bind_group(
|
||||
&self.extension,
|
||||
layout,
|
||||
render_device,
|
||||
extended_param,
|
||||
force_no_bindless,
|
||||
)?;
|
||||
|
||||
bindings.extend(extended_bindgroup.bindings.0);
|
||||
|
||||
|
@ -174,13 +192,23 @@ impl<B: Material, E: MaterialExtension> AsBindGroup for ExtendedMaterial<B, E> {
|
|||
|
||||
fn bind_group_layout_entries(
|
||||
render_device: &RenderDevice,
|
||||
mut force_no_bindless: bool,
|
||||
) -> Vec<bevy_render::render_resource::BindGroupLayoutEntry>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
// Only allow bindless mode if both the base material and the extension
|
||||
// support it.
|
||||
force_no_bindless = force_no_bindless
|
||||
|| B::BINDLESS_SLOT_COUNT.is_none()
|
||||
|| E::BINDLESS_SLOT_COUNT.is_none();
|
||||
|
||||
// add together the bindings of the standard material and the user material
|
||||
let mut entries = B::bind_group_layout_entries(render_device);
|
||||
entries.extend(E::bind_group_layout_entries(render_device));
|
||||
let mut entries = B::bind_group_layout_entries(render_device, force_no_bindless);
|
||||
entries.extend(E::bind_group_layout_entries(
|
||||
render_device,
|
||||
force_no_bindless,
|
||||
));
|
||||
entries
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1062,6 +1062,7 @@ impl<M: Material> RenderAsset for PreparedMaterial<M> {
|
|||
&pipeline.material_layout,
|
||||
render_device,
|
||||
material_param,
|
||||
false,
|
||||
) {
|
||||
Ok(unprepared) => {
|
||||
bind_group_allocator.init(render_device, *material_binding_id, unprepared);
|
||||
|
|
|
@ -767,7 +767,7 @@ where
|
|||
fn from_world(world: &mut World) -> Self {
|
||||
// Create a new bind group allocator.
|
||||
let render_device = world.resource::<RenderDevice>();
|
||||
let bind_group_layout_entries = M::bind_group_layout_entries(render_device);
|
||||
let bind_group_layout_entries = M::bind_group_layout_entries(render_device, false);
|
||||
let bind_group_layout =
|
||||
render_device.create_bind_group_layout(M::label(), &bind_group_layout_entries);
|
||||
let fallback_buffers =
|
||||
|
|
|
@ -31,6 +31,7 @@ pub enum UvChannel {
|
|||
#[derive(Asset, AsBindGroup, Reflect, Debug, Clone)]
|
||||
#[bind_group_data(StandardMaterialKey)]
|
||||
#[uniform(0, StandardMaterialUniform)]
|
||||
#[bindless(16)]
|
||||
#[reflect(Default, Debug)]
|
||||
pub struct StandardMaterial {
|
||||
/// The color of the surface of the material before lighting.
|
||||
|
|
|
@ -494,6 +494,11 @@ where
|
|||
shader_defs.push("HAS_PREVIOUS_MORPH".into());
|
||||
}
|
||||
|
||||
// If bindless mode is on, add a `BINDLESS` define.
|
||||
if self.material_pipeline.bindless {
|
||||
shader_defs.push("BINDLESS".into());
|
||||
}
|
||||
|
||||
if key
|
||||
.mesh_key
|
||||
.contains(MeshPipelineKey::VISIBILITY_RANGE_DITHER)
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
#define_import_path bevy_pbr::parallax_mapping
|
||||
|
||||
#import bevy_pbr::pbr_bindings::{depth_map_texture, depth_map_sampler}
|
||||
#import bevy_pbr::{
|
||||
pbr_bindings::{depth_map_texture, depth_map_sampler},
|
||||
mesh_bindings::mesh
|
||||
}
|
||||
|
||||
fn sample_depth_map(uv: vec2<f32>) -> f32 {
|
||||
fn sample_depth_map(uv: vec2<f32>, instance_index: u32) -> f32 {
|
||||
let slot = mesh[instance_index].material_bind_group_slot;
|
||||
// We use `textureSampleLevel` over `textureSample` because the wgpu DX12
|
||||
// backend (Fxc) panics when using "gradient instructions" inside a loop.
|
||||
// It results in the whole loop being unrolled by the shader compiler,
|
||||
|
@ -13,7 +17,17 @@ fn sample_depth_map(uv: vec2<f32>) -> f32 {
|
|||
// the MIP level, so no gradient instructions are used, and we can use
|
||||
// sample_depth_map in our loop.
|
||||
// See https://stackoverflow.com/questions/56581141/direct3d11-gradient-instruction-used-in-a-loop-with-varying-iteration-forcing
|
||||
return textureSampleLevel(depth_map_texture, depth_map_sampler, uv, 0.0).r;
|
||||
return textureSampleLevel(
|
||||
#ifdef BINDLESS
|
||||
depth_map_texture[slot],
|
||||
depth_map_sampler[slot],
|
||||
#else // BINDLESS
|
||||
depth_map_texture,
|
||||
depth_map_sampler,
|
||||
#endif // BINDLESS
|
||||
uv,
|
||||
0.0
|
||||
).r;
|
||||
}
|
||||
|
||||
// An implementation of parallax mapping, see https://en.wikipedia.org/wiki/Parallax_mapping
|
||||
|
@ -26,6 +40,7 @@ fn parallaxed_uv(
|
|||
original_uv: vec2<f32>,
|
||||
// The vector from the camera to the fragment at the surface in tangent space
|
||||
Vt: vec3<f32>,
|
||||
instance_index: u32,
|
||||
) -> vec2<f32> {
|
||||
if max_layer_count < 1.0 {
|
||||
return original_uv;
|
||||
|
@ -53,7 +68,7 @@ fn parallaxed_uv(
|
|||
var delta_uv = depth_scale * layer_depth * Vt.xy * vec2(1.0, -1.0) / view_steepness;
|
||||
|
||||
var current_layer_depth = 0.0;
|
||||
var texture_depth = sample_depth_map(uv);
|
||||
var texture_depth = sample_depth_map(uv, instance_index);
|
||||
|
||||
// texture_depth > current_layer_depth means the depth map depth is deeper
|
||||
// than the depth the ray would be at this UV offset so the ray has not
|
||||
|
@ -61,7 +76,7 @@ fn parallaxed_uv(
|
|||
for (var i: i32 = 0; texture_depth > current_layer_depth && i <= i32(layer_count); i++) {
|
||||
current_layer_depth += layer_depth;
|
||||
uv += delta_uv;
|
||||
texture_depth = sample_depth_map(uv);
|
||||
texture_depth = sample_depth_map(uv, instance_index);
|
||||
}
|
||||
|
||||
#ifdef RELIEF_MAPPING
|
||||
|
@ -79,7 +94,7 @@ fn parallaxed_uv(
|
|||
current_layer_depth -= delta_depth;
|
||||
|
||||
for (var i: u32 = 0u; i < max_steps; i++) {
|
||||
texture_depth = sample_depth_map(uv);
|
||||
texture_depth = sample_depth_map(uv, instance_index);
|
||||
|
||||
// Halve the deltas for the next step
|
||||
delta_uv *= 0.5;
|
||||
|
@ -103,7 +118,7 @@ fn parallaxed_uv(
|
|||
// may skip small details and result in writhing material artifacts.
|
||||
let previous_uv = uv - delta_uv;
|
||||
let next_depth = texture_depth - current_layer_depth;
|
||||
let previous_depth = sample_depth_map(previous_uv) - current_layer_depth + layer_depth;
|
||||
let previous_depth = sample_depth_map(previous_uv, instance_index) - current_layer_depth + layer_depth;
|
||||
|
||||
let weight = next_depth / (next_depth - previous_depth);
|
||||
|
||||
|
|
|
@ -2,6 +2,21 @@
|
|||
|
||||
#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;
|
||||
|
@ -15,23 +30,50 @@
|
|||
@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
|
||||
#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
|
||||
#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
|
||||
#endif // BINDLESS
|
||||
#endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
|
||||
|
|
|
@ -70,12 +70,23 @@ fn pbr_input_from_standard_material(
|
|||
in: VertexOutput,
|
||||
is_front: bool,
|
||||
) -> pbr_types::PbrInput {
|
||||
let double_sided = (pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u;
|
||||
#ifdef BINDLESS
|
||||
let slot = mesh[in.instance_index].material_bind_group_slot;
|
||||
let flags = pbr_bindings::material[slot].flags;
|
||||
let base_color = pbr_bindings::material[slot].base_color;
|
||||
let deferred_lighting_pass_id = pbr_bindings::material[slot].deferred_lighting_pass_id;
|
||||
#else // BINDLESS
|
||||
let flags = pbr_bindings::material.flags;
|
||||
let base_color = pbr_bindings::material.base_color;
|
||||
let deferred_lighting_pass_id = pbr_bindings::material.deferred_lighting_pass_id;
|
||||
#endif
|
||||
|
||||
let double_sided = (flags & pbr_types::STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u;
|
||||
|
||||
var pbr_input: pbr_types::PbrInput = pbr_input_from_vertex_output(in, is_front, double_sided);
|
||||
pbr_input.material.flags = pbr_bindings::material.flags;
|
||||
pbr_input.material.base_color *= pbr_bindings::material.base_color;
|
||||
pbr_input.material.deferred_lighting_pass_id = pbr_bindings::material.deferred_lighting_pass_id;
|
||||
pbr_input.material.flags = flags;
|
||||
pbr_input.material.base_color *= base_color;
|
||||
pbr_input.material.deferred_lighting_pass_id = deferred_lighting_pass_id;
|
||||
|
||||
// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
|
||||
let NdotV = max(dot(pbr_input.N, pbr_input.V), 0.0001);
|
||||
|
@ -91,7 +102,13 @@ fn pbr_input_from_standard_material(
|
|||
|
||||
// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
|
||||
#ifdef VERTEX_UVS
|
||||
|
||||
#ifdef BINDLESS
|
||||
let uv_transform = pbr_bindings::material[slot].uv_transform;
|
||||
#else // BINDLESS
|
||||
let uv_transform = pbr_bindings::material.uv_transform;
|
||||
#endif // BINDLESS
|
||||
|
||||
#ifdef VERTEX_UVS_A
|
||||
var uv = (uv_transform * vec3(in.uv, 1.0)).xy;
|
||||
#endif
|
||||
|
@ -104,7 +121,7 @@ fn pbr_input_from_standard_material(
|
|||
#endif
|
||||
|
||||
#ifdef VERTEX_TANGENTS
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_DEPTH_MAP_BIT) != 0u) {
|
||||
if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_DEPTH_MAP_BIT) != 0u) {
|
||||
let V = pbr_input.V;
|
||||
let TBN = pbr_functions::calculate_tbn_mikktspace(in.world_normal, in.world_tangent);
|
||||
let T = TBN[0];
|
||||
|
@ -115,28 +132,42 @@ fn pbr_input_from_standard_material(
|
|||
#ifdef VERTEX_UVS_A
|
||||
// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
|
||||
uv = parallaxed_uv(
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::material[slot].parallax_depth_scale,
|
||||
pbr_bindings::material[slot].max_parallax_layer_count,
|
||||
pbr_bindings::material[slot].max_relief_mapping_search_steps,
|
||||
#else // BINDLESS
|
||||
pbr_bindings::material.parallax_depth_scale,
|
||||
pbr_bindings::material.max_parallax_layer_count,
|
||||
pbr_bindings::material.max_relief_mapping_search_steps,
|
||||
#endif // BINDLESS
|
||||
uv,
|
||||
// Flip the direction of Vt to go toward the surface to make the
|
||||
// parallax mapping algorithm easier to understand and reason
|
||||
// about.
|
||||
-Vt,
|
||||
in.instance_index,
|
||||
);
|
||||
#endif
|
||||
|
||||
#ifdef VERTEX_UVS_B
|
||||
// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
|
||||
uv_b = parallaxed_uv(
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::material[slot].parallax_depth_scale,
|
||||
pbr_bindings::material[slot].max_parallax_layer_count,
|
||||
pbr_bindings::material[slot].max_relief_mapping_search_steps,
|
||||
#else // BINDLESS
|
||||
pbr_bindings::material.parallax_depth_scale,
|
||||
pbr_bindings::material.max_parallax_layer_count,
|
||||
pbr_bindings::material.max_relief_mapping_search_steps,
|
||||
#endif // BINDLESS
|
||||
uv_b,
|
||||
// Flip the direction of Vt to go toward the surface to make the
|
||||
// parallax mapping algorithm easier to understand and reason
|
||||
// about.
|
||||
-Vt,
|
||||
in.instance_index,
|
||||
);
|
||||
#else
|
||||
uv_b = uv;
|
||||
|
@ -144,27 +175,47 @@ fn pbr_input_from_standard_material(
|
|||
}
|
||||
#endif // VERTEX_TANGENTS
|
||||
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u) {
|
||||
pbr_input.material.base_color *= pbr_functions::sample_texture(
|
||||
pbr_bindings::base_color_texture,
|
||||
pbr_bindings::base_color_sampler,
|
||||
if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u) {
|
||||
pbr_input.material.base_color *=
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::base_color_texture[slot],
|
||||
pbr_bindings::base_color_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::base_color_texture,
|
||||
pbr_bindings::base_color_sampler,
|
||||
#endif // BINDLESS
|
||||
#ifdef STANDARD_MATERIAL_BASE_COLOR_UV_B
|
||||
uv_b,
|
||||
uv_b,
|
||||
#else
|
||||
uv,
|
||||
uv,
|
||||
#endif
|
||||
bias,
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
);
|
||||
|
||||
#ifdef ALPHA_TO_COVERAGE
|
||||
// Sharpen alpha edges.
|
||||
//
|
||||
// https://bgolus.medium.com/anti-aliased-alpha-test-the-esoteric-alpha-to-coverage-8b177335ae4f
|
||||
let alpha_mode = pbr_bindings::material.flags &
|
||||
pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS;
|
||||
let alpha_mode = flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS;
|
||||
if alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_ALPHA_TO_COVERAGE {
|
||||
pbr_input.material.base_color.a = (pbr_input.material.base_color.a -
|
||||
pbr_bindings::material.alpha_cutoff) /
|
||||
|
||||
#ifdef BINDLESS
|
||||
let alpha_cutoff = pbr_bindings::material[slot].alpha_cutoff;
|
||||
#else // BINDLESS
|
||||
let alpha_cutoff = pbr_bindings::material.alpha_cutoff;
|
||||
#endif // BINDLESS
|
||||
|
||||
pbr_input.material.base_color.a = (pbr_input.material.base_color.a - alpha_cutoff) /
|
||||
max(fwidth(pbr_input.material.base_color.a), 0.0001) + 0.5;
|
||||
}
|
||||
#endif // ALPHA_TO_COVERAGE
|
||||
|
@ -172,50 +223,100 @@ fn pbr_input_from_standard_material(
|
|||
}
|
||||
#endif // VERTEX_UVS
|
||||
|
||||
pbr_input.material.flags = pbr_bindings::material.flags;
|
||||
pbr_input.material.flags = flags;
|
||||
|
||||
// NOTE: Unlit bit not set means == 0 is true, so the true case is if lit
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u) {
|
||||
if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u) {
|
||||
#ifdef BINDLESS
|
||||
pbr_input.material.reflectance = pbr_bindings::material[slot].reflectance;
|
||||
pbr_input.material.ior = pbr_bindings::material[slot].ior;
|
||||
pbr_input.material.attenuation_color = pbr_bindings::material[slot].attenuation_color;
|
||||
pbr_input.material.attenuation_distance = pbr_bindings::material[slot].attenuation_distance;
|
||||
pbr_input.material.alpha_cutoff = pbr_bindings::material[slot].alpha_cutoff;
|
||||
#else // BINDLESS
|
||||
pbr_input.material.reflectance = pbr_bindings::material.reflectance;
|
||||
pbr_input.material.ior = pbr_bindings::material.ior;
|
||||
pbr_input.material.attenuation_color = pbr_bindings::material.attenuation_color;
|
||||
pbr_input.material.attenuation_distance = pbr_bindings::material.attenuation_distance;
|
||||
pbr_input.material.alpha_cutoff = pbr_bindings::material.alpha_cutoff;
|
||||
#endif // BINDLESS
|
||||
|
||||
// emissive
|
||||
#ifdef BINDLESS
|
||||
var emissive: vec4<f32> = pbr_bindings::material[slot].emissive;
|
||||
#else // BINDLESS
|
||||
var emissive: vec4<f32> = pbr_bindings::material.emissive;
|
||||
#endif // BINDLESS
|
||||
|
||||
#ifdef VERTEX_UVS
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_EMISSIVE_TEXTURE_BIT) != 0u) {
|
||||
emissive = vec4<f32>(emissive.rgb * pbr_functions::sample_texture(
|
||||
pbr_bindings::emissive_texture,
|
||||
pbr_bindings::emissive_sampler,
|
||||
if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_EMISSIVE_TEXTURE_BIT) != 0u) {
|
||||
emissive = vec4<f32>(emissive.rgb *
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::emissive_texture[slot],
|
||||
pbr_bindings::emissive_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::emissive_texture,
|
||||
pbr_bindings::emissive_sampler,
|
||||
#endif // BINDLESS
|
||||
#ifdef STANDARD_MATERIAL_EMISSIVE_UV_B
|
||||
uv_b,
|
||||
uv_b,
|
||||
#else
|
||||
uv,
|
||||
uv,
|
||||
#endif
|
||||
bias,
|
||||
).rgb, emissive.a);
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
).rgb,
|
||||
emissive.a);
|
||||
}
|
||||
#endif
|
||||
pbr_input.material.emissive = emissive;
|
||||
|
||||
// metallic and perceptual roughness
|
||||
#ifdef BINDLESS
|
||||
var metallic: f32 = pbr_bindings::material[slot].metallic;
|
||||
var perceptual_roughness: f32 = pbr_bindings::material[slot].perceptual_roughness;
|
||||
#else // BINDLESS
|
||||
var metallic: f32 = pbr_bindings::material.metallic;
|
||||
var perceptual_roughness: f32 = pbr_bindings::material.perceptual_roughness;
|
||||
#endif // BINDLESS
|
||||
|
||||
let roughness = lighting::perceptualRoughnessToRoughness(perceptual_roughness);
|
||||
#ifdef VERTEX_UVS
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_METALLIC_ROUGHNESS_TEXTURE_BIT) != 0u) {
|
||||
let metallic_roughness = pbr_functions::sample_texture(
|
||||
pbr_bindings::metallic_roughness_texture,
|
||||
pbr_bindings::metallic_roughness_sampler,
|
||||
if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_METALLIC_ROUGHNESS_TEXTURE_BIT) != 0u) {
|
||||
let metallic_roughness =
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::metallic_roughness_texture[slot],
|
||||
pbr_bindings::metallic_roughness_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::metallic_roughness_texture,
|
||||
pbr_bindings::metallic_roughness_sampler,
|
||||
#endif // BINDLESS
|
||||
#ifdef STANDARD_MATERIAL_METALLIC_ROUGHNESS_UV_B
|
||||
uv_b,
|
||||
uv_b,
|
||||
#else
|
||||
uv,
|
||||
uv,
|
||||
#endif
|
||||
bias,
|
||||
);
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
);
|
||||
// Sampling from GLTF standard channels for now
|
||||
metallic *= metallic_roughness.b;
|
||||
perceptual_roughness *= metallic_roughness.g;
|
||||
|
@ -225,76 +326,158 @@ fn pbr_input_from_standard_material(
|
|||
pbr_input.material.perceptual_roughness = perceptual_roughness;
|
||||
|
||||
// Clearcoat factor
|
||||
#ifdef BINDLESS
|
||||
pbr_input.material.clearcoat = pbr_bindings::material[slot].clearcoat;
|
||||
#else // BINDLESS
|
||||
pbr_input.material.clearcoat = pbr_bindings::material.clearcoat;
|
||||
#endif // BINDLESS
|
||||
|
||||
#ifdef VERTEX_UVS
|
||||
#ifdef PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_CLEARCOAT_TEXTURE_BIT) != 0u) {
|
||||
pbr_input.material.clearcoat *= pbr_functions::sample_texture(
|
||||
pbr_bindings::clearcoat_texture,
|
||||
pbr_bindings::clearcoat_sampler,
|
||||
if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_CLEARCOAT_TEXTURE_BIT) != 0u) {
|
||||
pbr_input.material.clearcoat *=
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::clearcoat_texture[slot],
|
||||
pbr_bindings::clearcoat_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::clearcoat_texture,
|
||||
pbr_bindings::clearcoat_sampler,
|
||||
#endif // BINDLESS
|
||||
#ifdef STANDARD_MATERIAL_CLEARCOAT_UV_B
|
||||
uv_b,
|
||||
uv_b,
|
||||
#else
|
||||
uv,
|
||||
uv,
|
||||
#endif
|
||||
bias,
|
||||
).r;
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
).r;
|
||||
}
|
||||
#endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
|
||||
#endif // VERTEX_UVS
|
||||
|
||||
// Clearcoat roughness
|
||||
pbr_input.material.clearcoat_perceptual_roughness = pbr_bindings::material.clearcoat_perceptual_roughness;
|
||||
#ifdef BINDLESS
|
||||
pbr_input.material.clearcoat_perceptual_roughness =
|
||||
pbr_bindings::material[slot].clearcoat_perceptual_roughness;
|
||||
#else // BINDLESS
|
||||
pbr_input.material.clearcoat_perceptual_roughness =
|
||||
pbr_bindings::material.clearcoat_perceptual_roughness;
|
||||
#endif // BINDLESS
|
||||
|
||||
#ifdef VERTEX_UVS
|
||||
#ifdef PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_CLEARCOAT_ROUGHNESS_TEXTURE_BIT) != 0u) {
|
||||
pbr_input.material.clearcoat_perceptual_roughness *= pbr_functions::sample_texture(
|
||||
pbr_bindings::clearcoat_roughness_texture,
|
||||
pbr_bindings::clearcoat_roughness_sampler,
|
||||
if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_CLEARCOAT_ROUGHNESS_TEXTURE_BIT) != 0u) {
|
||||
pbr_input.material.clearcoat_perceptual_roughness *=
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::clearcoat_roughness_texture[slot],
|
||||
pbr_bindings::clearcoat_roughness_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::clearcoat_roughness_texture,
|
||||
pbr_bindings::clearcoat_roughness_sampler,
|
||||
#endif // BINDLESS
|
||||
#ifdef STANDARD_MATERIAL_CLEARCOAT_ROUGHNESS_UV_B
|
||||
uv_b,
|
||||
uv_b,
|
||||
#else
|
||||
uv,
|
||||
uv,
|
||||
#endif
|
||||
bias,
|
||||
).g;
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
).g;
|
||||
}
|
||||
#endif // PBR_MULTI_LAYER_MATERIAL_TEXTURES_SUPPORTED
|
||||
#endif // VERTEX_UVS
|
||||
|
||||
#ifdef BINDLESS
|
||||
var specular_transmission: f32 = pbr_bindings::material[slot].specular_transmission;
|
||||
#else // BINDLESS
|
||||
var specular_transmission: f32 = pbr_bindings::material.specular_transmission;
|
||||
#endif // BINDLESS
|
||||
|
||||
#ifdef VERTEX_UVS
|
||||
#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_SPECULAR_TRANSMISSION_TEXTURE_BIT) != 0u) {
|
||||
specular_transmission *= pbr_functions::sample_texture(
|
||||
pbr_bindings::specular_transmission_texture,
|
||||
pbr_bindings::specular_transmission_sampler,
|
||||
if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_SPECULAR_TRANSMISSION_TEXTURE_BIT) != 0u) {
|
||||
specular_transmission *=
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::specular_transmission_texture[slot],
|
||||
pbr_bindings::specular_transmission_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::specular_transmission_texture,
|
||||
pbr_bindings::specular_transmission_sampler,
|
||||
#endif // BINDLESS
|
||||
#ifdef STANDARD_MATERIAL_SPECULAR_TRANSMISSION_UV_B
|
||||
uv_b,
|
||||
uv_b,
|
||||
#else
|
||||
uv,
|
||||
uv,
|
||||
#endif
|
||||
bias,
|
||||
).r;
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
).r;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
pbr_input.material.specular_transmission = specular_transmission;
|
||||
|
||||
#ifdef BINDLESS
|
||||
var thickness: f32 = pbr_bindings::material[slot].thickness;
|
||||
#else // BINDLESS
|
||||
var thickness: f32 = pbr_bindings::material.thickness;
|
||||
#endif // BINDLESS
|
||||
|
||||
#ifdef VERTEX_UVS
|
||||
#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_THICKNESS_TEXTURE_BIT) != 0u) {
|
||||
thickness *= pbr_functions::sample_texture(
|
||||
pbr_bindings::thickness_texture,
|
||||
pbr_bindings::thickness_sampler,
|
||||
if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_THICKNESS_TEXTURE_BIT) != 0u) {
|
||||
thickness *=
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::thickness_texture[slot],
|
||||
pbr_bindings::thickness_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::thickness_texture,
|
||||
pbr_bindings::thickness_sampler,
|
||||
#endif // BINDLESS
|
||||
#ifdef STANDARD_MATERIAL_THICKNESS_UV_B
|
||||
uv_b,
|
||||
uv_b,
|
||||
#else
|
||||
uv,
|
||||
uv,
|
||||
#endif
|
||||
bias,
|
||||
).g;
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
).g;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -307,20 +490,40 @@ fn pbr_input_from_standard_material(
|
|||
#endif
|
||||
pbr_input.material.thickness = thickness;
|
||||
|
||||
#ifdef BINDLESS
|
||||
var diffuse_transmission = pbr_bindings::material[slot].diffuse_transmission;
|
||||
#else // BINDLESS
|
||||
var diffuse_transmission = pbr_bindings::material.diffuse_transmission;
|
||||
#endif // BINDLESS
|
||||
|
||||
#ifdef VERTEX_UVS
|
||||
#ifdef PBR_TRANSMISSION_TEXTURES_SUPPORTED
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_DIFFUSE_TRANSMISSION_TEXTURE_BIT) != 0u) {
|
||||
diffuse_transmission *= pbr_functions::sample_texture(
|
||||
pbr_bindings::diffuse_transmission_texture,
|
||||
pbr_bindings::diffuse_transmission_sampler,
|
||||
if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_DIFFUSE_TRANSMISSION_TEXTURE_BIT) != 0u) {
|
||||
diffuse_transmission *=
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::diffuse_transmission_texture[slot],
|
||||
pbr_bindings::diffuse_transmission_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::diffuse_transmission_texture,
|
||||
pbr_bindings::diffuse_transmission_sampler,
|
||||
#endif // BINDLESS
|
||||
#ifdef STANDARD_MATERIAL_DIFFUSE_TRANSMISSION_UV_B
|
||||
uv_b,
|
||||
uv_b,
|
||||
#else
|
||||
uv,
|
||||
uv,
|
||||
#endif
|
||||
bias,
|
||||
).a;
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
).a;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -329,17 +532,32 @@ fn pbr_input_from_standard_material(
|
|||
var diffuse_occlusion: vec3<f32> = vec3(1.0);
|
||||
var specular_occlusion: f32 = 1.0;
|
||||
#ifdef VERTEX_UVS
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_OCCLUSION_TEXTURE_BIT) != 0u) {
|
||||
diffuse_occlusion *= pbr_functions::sample_texture(
|
||||
pbr_bindings::occlusion_texture,
|
||||
pbr_bindings::occlusion_sampler,
|
||||
if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_OCCLUSION_TEXTURE_BIT) != 0u) {
|
||||
diffuse_occlusion *=
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::occlusion_texture[slot],
|
||||
pbr_bindings::occlusion_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::occlusion_texture,
|
||||
pbr_bindings::occlusion_sampler,
|
||||
#endif // BINDLESS
|
||||
#ifdef STANDARD_MATERIAL_OCCLUSION_UV_B
|
||||
uv_b,
|
||||
uv_b,
|
||||
#else
|
||||
uv,
|
||||
uv,
|
||||
#endif
|
||||
bias,
|
||||
).r;
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
).r;
|
||||
}
|
||||
#endif
|
||||
#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
|
||||
|
@ -366,24 +584,33 @@ fn pbr_input_from_standard_material(
|
|||
|
||||
#ifdef STANDARD_MATERIAL_NORMAL_MAP
|
||||
|
||||
let Nt = pbr_functions::sample_texture(
|
||||
pbr_bindings::normal_map_texture,
|
||||
pbr_bindings::normal_map_sampler,
|
||||
let Nt =
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::normal_map_texture[slot],
|
||||
pbr_bindings::normal_map_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::normal_map_texture,
|
||||
pbr_bindings::normal_map_sampler,
|
||||
#endif // BINDLESS
|
||||
#ifdef STANDARD_MATERIAL_NORMAL_MAP_UV_B
|
||||
uv_b,
|
||||
#else
|
||||
uv,
|
||||
#endif
|
||||
bias,
|
||||
).rgb;
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
).rgb;
|
||||
|
||||
pbr_input.N = pbr_functions::apply_normal_mapping(
|
||||
pbr_bindings::material.flags,
|
||||
TBN,
|
||||
double_sided,
|
||||
is_front,
|
||||
Nt,
|
||||
);
|
||||
pbr_input.N = pbr_functions::apply_normal_mapping(flags, TBN, double_sided, is_front, Nt);
|
||||
|
||||
#endif // STANDARD_MATERIAL_NORMAL_MAP
|
||||
|
||||
|
@ -395,19 +622,34 @@ fn pbr_input_from_standard_material(
|
|||
|
||||
#ifdef STANDARD_MATERIAL_CLEARCOAT_NORMAL_MAP
|
||||
|
||||
let clearcoat_Nt = pbr_functions::sample_texture(
|
||||
pbr_bindings::clearcoat_normal_texture,
|
||||
pbr_bindings::clearcoat_normal_sampler,
|
||||
let clearcoat_Nt =
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::clearcoat_normal_texture[slot],
|
||||
pbr_bindings::clearcoat_normal_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::clearcoat_normal_texture,
|
||||
pbr_bindings::clearcoat_normal_sampler,
|
||||
#endif // BINDLESS
|
||||
#ifdef STANDARD_MATERIAL_CLEARCOAT_NORMAL_UV_B
|
||||
uv_b,
|
||||
#else
|
||||
uv,
|
||||
#endif
|
||||
bias,
|
||||
).rgb;
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
).rgb;
|
||||
|
||||
pbr_input.clearcoat_N = pbr_functions::apply_normal_mapping(
|
||||
pbr_bindings::material.flags,
|
||||
flags,
|
||||
TBN,
|
||||
double_sided,
|
||||
is_front,
|
||||
|
@ -429,21 +671,41 @@ fn pbr_input_from_standard_material(
|
|||
#ifdef VERTEX_TANGENTS
|
||||
#ifdef STANDARD_MATERIAL_ANISOTROPY
|
||||
|
||||
#ifdef BINDLESS
|
||||
var anisotropy_strength = pbr_bindings::material[slot].anisotropy_strength;
|
||||
var anisotropy_direction = pbr_bindings::material[slot].anisotropy_rotation;
|
||||
#else // BINDLESS
|
||||
var anisotropy_strength = pbr_bindings::material.anisotropy_strength;
|
||||
var anisotropy_direction = pbr_bindings::material.anisotropy_rotation;
|
||||
#endif // BINDLESS
|
||||
|
||||
// Adjust based on the anisotropy map if there is one.
|
||||
if ((pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_ANISOTROPY_TEXTURE_BIT) != 0u) {
|
||||
let anisotropy_texel = pbr_functions::sample_texture(
|
||||
pbr_bindings::anisotropy_texture,
|
||||
pbr_bindings::anisotropy_sampler,
|
||||
if ((flags & pbr_types::STANDARD_MATERIAL_FLAGS_ANISOTROPY_TEXTURE_BIT) != 0u) {
|
||||
let anisotropy_texel =
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::anisotropy_texture[slot],
|
||||
pbr_bindings::anisotropy_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::anisotropy_texture,
|
||||
pbr_bindings::anisotropy_sampler,
|
||||
#endif
|
||||
#ifdef STANDARD_MATERIAL_ANISOTROPY_UV_B
|
||||
uv_b,
|
||||
uv_b,
|
||||
#else // STANDARD_MATERIAL_ANISOTROPY_UV_B
|
||||
uv,
|
||||
uv,
|
||||
#endif // STANDARD_MATERIAL_ANISOTROPY_UV_B
|
||||
bias,
|
||||
).rgb;
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
).rgb;
|
||||
|
||||
let anisotropy_direction_from_texture = normalize(anisotropy_texel.rg * 2.0 - 1.0);
|
||||
// Rotate by the anisotropy direction.
|
||||
|
@ -468,10 +730,14 @@ fn pbr_input_from_standard_material(
|
|||
|
||||
// TODO: Meshlet support
|
||||
#ifdef LIGHTMAP
|
||||
pbr_input.lightmap_light = lightmap(
|
||||
in.uv_b,
|
||||
pbr_bindings::material.lightmap_exposure,
|
||||
in.instance_index);
|
||||
|
||||
#ifdef BINDLESS
|
||||
let lightmap_exposure = pbr_bindings::material[slot].lightmap_exposure;
|
||||
#else // BINDLESS
|
||||
let lightmap_exposure = pbr_bindings::material.lightmap_exposure;
|
||||
#endif // BINDLESS
|
||||
|
||||
pbr_input.lightmap_light = lightmap(in.uv_b, lightmap_exposure, in.instance_index);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -121,21 +121,6 @@ fn alpha_discard(material: pbr_types::StandardMaterial, output_color: vec4<f32>)
|
|||
return color;
|
||||
}
|
||||
|
||||
// Samples a texture using the appropriate biasing metric for the type of mesh
|
||||
// in use (mesh vs. meshlet).
|
||||
fn sample_texture(
|
||||
texture: texture_2d<f32>,
|
||||
samp: sampler,
|
||||
uv: vec2<f32>,
|
||||
bias: SampleBias,
|
||||
) -> vec4<f32> {
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
return textureSampleGrad(texture, samp, uv, bias.ddx_uv, bias.ddy_uv);
|
||||
#else
|
||||
return textureSampleBias(texture, samp, uv, bias.mip_bias);
|
||||
#endif
|
||||
}
|
||||
|
||||
fn prepare_world_normal(
|
||||
world_normal: vec3<f32>,
|
||||
double_sided: bool,
|
||||
|
|
|
@ -76,12 +76,27 @@ fn fragment(
|
|||
bias.mip_bias = view.mip_bias;
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
|
||||
let Nt = pbr_functions::sample_texture(
|
||||
pbr_bindings::normal_map_texture,
|
||||
pbr_bindings::normal_map_sampler,
|
||||
uv,
|
||||
bias,
|
||||
).rgb;
|
||||
let Nt =
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleGrad(
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
textureSampleBias(
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::normal_map_texture[slot],
|
||||
pbr_bindings::normal_map_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::normal_map_texture,
|
||||
pbr_bindings::normal_map_sampler,
|
||||
#endif // BINDLESS
|
||||
uv,
|
||||
#ifdef MESHLET_MESH_MATERIAL_PASS
|
||||
bias.ddx_uv,
|
||||
bias.ddy_uv,
|
||||
#else // MESHLET_MESH_MATERIAL_PASS
|
||||
bias.mip_bias,
|
||||
#endif // MESHLET_MESH_MATERIAL_PASS
|
||||
).rgb;
|
||||
let TBN = pbr_functions::calculate_tbn_mikktspace(normal, in.world_tangent);
|
||||
|
||||
normal = pbr_functions::apply_normal_mapping(
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#import bevy_pbr::{
|
||||
prepass_io::VertexOutput,
|
||||
prepass_bindings::previous_view_uniforms,
|
||||
mesh_bindings::mesh,
|
||||
mesh_view_bindings::view,
|
||||
pbr_bindings,
|
||||
pbr_types,
|
||||
|
@ -15,7 +16,12 @@ const PREMULTIPLIED_ALPHA_CUTOFF = 0.05;
|
|||
fn prepass_alpha_discard(in: VertexOutput) {
|
||||
|
||||
#ifdef MAY_DISCARD
|
||||
#ifdef BINDLESS
|
||||
let slot = mesh[in.instance_index].material_bind_group_slot;
|
||||
var output_color: vec4<f32> = pbr_bindings::material[slot].base_color;
|
||||
#else // BINDLESS
|
||||
var output_color: vec4<f32> = pbr_bindings::material.base_color;
|
||||
#endif // BINDLESS
|
||||
|
||||
#ifdef VERTEX_UVS
|
||||
#ifdef STANDARD_MATERIAL_BASE_COLOR_UV_B
|
||||
|
@ -24,16 +30,38 @@ fn prepass_alpha_discard(in: VertexOutput) {
|
|||
var uv = in.uv;
|
||||
#endif // STANDARD_MATERIAL_BASE_COLOR_UV_B
|
||||
|
||||
#ifdef BINDLESS
|
||||
let uv_transform = pbr_bindings::material[slot].uv_transform;
|
||||
let flags = pbr_bindings::material[slot].flags;
|
||||
#else // BINDLESS
|
||||
let uv_transform = pbr_bindings::material.uv_transform;
|
||||
let flags = pbr_bindings::material.flags;
|
||||
#endif // BINDLESS
|
||||
|
||||
uv = (uv_transform * vec3(uv, 1.0)).xy;
|
||||
if (pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u {
|
||||
output_color = output_color * textureSampleBias(pbr_bindings::base_color_texture, pbr_bindings::base_color_sampler, uv, view.mip_bias);
|
||||
if (flags & pbr_types::STANDARD_MATERIAL_FLAGS_BASE_COLOR_TEXTURE_BIT) != 0u {
|
||||
output_color = output_color * textureSampleBias(
|
||||
#ifdef BINDLESS
|
||||
pbr_bindings::base_color_texture[slot],
|
||||
pbr_bindings::base_color_sampler[slot],
|
||||
#else // BINDLESS
|
||||
pbr_bindings::base_color_texture,
|
||||
pbr_bindings::base_color_sampler,
|
||||
#endif // BINDLESS
|
||||
uv,
|
||||
view.mip_bias
|
||||
);
|
||||
}
|
||||
#endif // VERTEX_UVS
|
||||
|
||||
let alpha_mode = pbr_bindings::material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS;
|
||||
let alpha_mode = flags & pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_RESERVED_BITS;
|
||||
if alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_MASK {
|
||||
if output_color.a < pbr_bindings::material.alpha_cutoff {
|
||||
#ifdef BINDLESS
|
||||
let alpha_cutoff = pbr_bindings::material[slot].alpha_cutoff;
|
||||
#else // BINDLESS
|
||||
let alpha_cutoff = pbr_bindings::material.alpha_cutoff;
|
||||
#endif // BINDLESS
|
||||
if output_color.a < alpha_cutoff {
|
||||
discard;
|
||||
}
|
||||
} else if (alpha_mode == pbr_types::STANDARD_MATERIAL_FLAGS_ALPHA_MODE_BLEND ||
|
||||
|
|
|
@ -443,7 +443,8 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
|
|||
if render_device.features().contains(
|
||||
#render_path::settings::WgpuFeatures::BUFFER_BINDING_ARRAY |
|
||||
#render_path::settings::WgpuFeatures::TEXTURE_BINDING_ARRAY
|
||||
) && render_device.limits().max_storage_buffers_per_shader_stage > 0 {
|
||||
) && render_device.limits().max_storage_buffers_per_shader_stage > 0 &&
|
||||
!force_no_bindless {
|
||||
(
|
||||
#render_path::render_resource::BufferBindingType::Storage { read_only: true },
|
||||
#render_path::render_resource::BufferUsages::STORAGE,
|
||||
|
@ -571,7 +572,8 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
|
|||
let #actual_bindless_slot_count = if render_device.features().contains(
|
||||
#render_path::settings::WgpuFeatures::BUFFER_BINDING_ARRAY |
|
||||
#render_path::settings::WgpuFeatures::TEXTURE_BINDING_ARRAY
|
||||
) && render_device.limits().max_storage_buffers_per_shader_stage > 0 {
|
||||
) && render_device.limits().max_storage_buffers_per_shader_stage > 0 &&
|
||||
!force_no_bindless {
|
||||
::core::num::NonZeroU32::new(#bindless_count)
|
||||
} else {
|
||||
None
|
||||
|
@ -607,6 +609,7 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
|
|||
layout: &#render_path::render_resource::BindGroupLayout,
|
||||
render_device: &#render_path::renderer::RenderDevice,
|
||||
(images, fallback_image, storage_buffers): &mut #ecs_path::system::SystemParamItem<'_, '_, Self::Param>,
|
||||
force_no_bindless: bool,
|
||||
) -> Result<#render_path::render_resource::UnpreparedBindGroup<Self::Data>, #render_path::render_resource::AsBindGroupError> {
|
||||
#uniform_binding_type_declarations
|
||||
|
||||
|
@ -618,7 +621,10 @@ pub fn derive_as_bind_group(ast: syn::DeriveInput) -> Result<TokenStream> {
|
|||
})
|
||||
}
|
||||
|
||||
fn bind_group_layout_entries(render_device: &#render_path::renderer::RenderDevice) -> Vec<#render_path::render_resource::BindGroupLayoutEntry> {
|
||||
fn bind_group_layout_entries(
|
||||
render_device: &#render_path::renderer::RenderDevice,
|
||||
force_no_bindless: bool
|
||||
) -> Vec<#render_path::render_resource::BindGroupLayoutEntry> {
|
||||
#actual_bindless_slot_count_declaration
|
||||
#uniform_binding_type_declarations
|
||||
|
||||
|
|
|
@ -352,7 +352,7 @@ pub trait AsBindGroup {
|
|||
param: &mut SystemParamItem<'_, '_, Self::Param>,
|
||||
) -> Result<PreparedBindGroup<Self::Data>, AsBindGroupError> {
|
||||
let UnpreparedBindGroup { bindings, data } =
|
||||
Self::unprepared_bind_group(self, layout, render_device, param)?;
|
||||
Self::unprepared_bind_group(self, layout, render_device, param, false)?;
|
||||
|
||||
let entries = bindings
|
||||
.iter()
|
||||
|
@ -372,30 +372,45 @@ pub trait AsBindGroup {
|
|||
}
|
||||
|
||||
/// Returns a vec of (binding index, `OwnedBindingResource`).
|
||||
/// In cases where `OwnedBindingResource` is not available (as for bindless texture arrays currently),
|
||||
/// an implementor may return `AsBindGroupError::CreateBindGroupDirectly`
|
||||
/// from this function and instead define `as_bind_group` directly. This may
|
||||
/// prevent certain features, such as bindless mode, from working correctly.
|
||||
///
|
||||
/// In cases where `OwnedBindingResource` is not available (as for bindless
|
||||
/// texture arrays currently), an implementor may return
|
||||
/// `AsBindGroupError::CreateBindGroupDirectly` from this function and
|
||||
/// instead define `as_bind_group` directly. This may prevent certain
|
||||
/// features, such as bindless mode, from working correctly.
|
||||
///
|
||||
/// Set `force_no_bindless` to true to require that bindless textures *not*
|
||||
/// be used. `ExtendedMaterial` uses this in order to ensure that the base
|
||||
/// material doesn't use bindless mode if the extension doesn't.
|
||||
fn unprepared_bind_group(
|
||||
&self,
|
||||
layout: &BindGroupLayout,
|
||||
render_device: &RenderDevice,
|
||||
param: &mut SystemParamItem<'_, '_, Self::Param>,
|
||||
force_no_bindless: bool,
|
||||
) -> Result<UnpreparedBindGroup<Self::Data>, AsBindGroupError>;
|
||||
|
||||
/// Creates the bind group layout matching all bind groups returned by [`AsBindGroup::as_bind_group`]
|
||||
/// Creates the bind group layout matching all bind groups returned by
|
||||
/// [`AsBindGroup::as_bind_group`]
|
||||
fn bind_group_layout(render_device: &RenderDevice) -> BindGroupLayout
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
render_device.create_bind_group_layout(
|
||||
Self::label(),
|
||||
&Self::bind_group_layout_entries(render_device),
|
||||
&Self::bind_group_layout_entries(render_device, false),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns a vec of bind group layout entries
|
||||
fn bind_group_layout_entries(render_device: &RenderDevice) -> Vec<BindGroupLayoutEntry>
|
||||
///
|
||||
/// Set `force_no_bindless` to true to require that bindless textures *not*
|
||||
/// be used. `ExtendedMaterial` uses this in order to ensure that the base
|
||||
/// material doesn't use bindless mode if the extension doesn't.
|
||||
fn bind_group_layout_entries(
|
||||
render_device: &RenderDevice,
|
||||
force_no_bindless: bool,
|
||||
) -> Vec<BindGroupLayoutEntry>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
|
|
@ -144,6 +144,7 @@ impl AsBindGroup for BindlessMaterial {
|
|||
_layout: &BindGroupLayout,
|
||||
_render_device: &RenderDevice,
|
||||
_param: &mut SystemParamItem<'_, '_, Self::Param>,
|
||||
_force_no_bindless: bool,
|
||||
) -> Result<UnpreparedBindGroup<Self::Data>, AsBindGroupError> {
|
||||
// We implement `as_bind_group`` directly because bindless texture
|
||||
// arrays can't be owned.
|
||||
|
@ -152,7 +153,7 @@ impl AsBindGroup for BindlessMaterial {
|
|||
Err(AsBindGroupError::CreateBindGroupDirectly)
|
||||
}
|
||||
|
||||
fn bind_group_layout_entries(_: &RenderDevice) -> Vec<BindGroupLayoutEntry>
|
||||
fn bind_group_layout_entries(_: &RenderDevice, _: bool) -> Vec<BindGroupLayoutEntry>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue