mirror of
https://github.com/bevyengine/bevy
synced 2025-01-02 00:08:53 +00:00
9cc7e7c080
* Save 16 bytes per vertex by calculating tangents in the shader at runtime, rather than storing them in the vertex data. * Based on https://jcgt.org/published/0009/03/04, https://www.jeremyong.com/graphics/2023/12/16/surface-gradient-bump-mapping. * Fixed visbuffer resolve to use the updated algorithm that flips ddy correctly * Added some more docs about meshlet material limitations, and some TODOs about transforming UV coordinates for the future. ![image](https://github.com/user-attachments/assets/222d8192-8c82-4d77-945d-53670a503761) For testing add a normal map to the bunnies with StandardMaterial like below, and then test that on both main and this PR (make sure to download the correct bunny for each). Results should be mostly identical. ```rust normal_map_texture: Some(asset_server.load_with_settings( "textures/BlueNoise-Normal.png", |settings: &mut ImageLoaderSettings| settings.is_srgb = false, )), ```
113 lines
3.1 KiB
WebGPU Shading Language
113 lines
3.1 KiB
WebGPU Shading Language
#import bevy_pbr::{
|
|
pbr_prepass_functions,
|
|
pbr_bindings,
|
|
pbr_bindings::material,
|
|
pbr_types,
|
|
pbr_functions,
|
|
pbr_functions::SampleBias,
|
|
prepass_io,
|
|
mesh_view_bindings::view,
|
|
}
|
|
|
|
#ifdef MESHLET_MESH_MATERIAL_PASS
|
|
#import bevy_pbr::meshlet_visibility_buffer_resolve::resolve_vertex_output
|
|
#endif
|
|
|
|
#ifdef PREPASS_FRAGMENT
|
|
@fragment
|
|
fn fragment(
|
|
#ifdef MESHLET_MESH_MATERIAL_PASS
|
|
@builtin(position) frag_coord: vec4<f32>,
|
|
#else
|
|
in: prepass_io::VertexOutput,
|
|
@builtin(front_facing) is_front: bool,
|
|
#endif
|
|
) -> prepass_io::FragmentOutput {
|
|
#ifdef MESHLET_MESH_MATERIAL_PASS
|
|
let in = resolve_vertex_output(frag_coord);
|
|
let is_front = true;
|
|
#else
|
|
pbr_prepass_functions::prepass_alpha_discard(in);
|
|
#endif
|
|
|
|
var out: prepass_io::FragmentOutput;
|
|
|
|
#ifdef DEPTH_CLAMP_ORTHO
|
|
out.frag_depth = in.clip_position_unclamped.z;
|
|
#endif // DEPTH_CLAMP_ORTHO
|
|
|
|
#ifdef NORMAL_PREPASS
|
|
// NOTE: Unlit bit not set means == 0 is true, so the true case is if lit
|
|
if (material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_UNLIT_BIT) == 0u {
|
|
let double_sided = (material.flags & pbr_types::STANDARD_MATERIAL_FLAGS_DOUBLE_SIDED_BIT) != 0u;
|
|
|
|
let world_normal = pbr_functions::prepare_world_normal(
|
|
in.world_normal,
|
|
double_sided,
|
|
is_front,
|
|
);
|
|
|
|
var normal = world_normal;
|
|
|
|
#ifdef VERTEX_UVS
|
|
#ifdef VERTEX_TANGENTS
|
|
#ifdef STANDARD_MATERIAL_NORMAL_MAP
|
|
|
|
// TODO: Transforming UVs mean we need to apply derivative chain rule for meshlet mesh material pass
|
|
#ifdef STANDARD_MATERIAL_NORMAL_MAP_UV_B
|
|
let uv = (material.uv_transform * vec3(in.uv_b, 1.0)).xy;
|
|
#else
|
|
let uv = (material.uv_transform * vec3(in.uv, 1.0)).xy;
|
|
#endif
|
|
|
|
// Fill in the sample bias so we can sample from textures.
|
|
var bias: SampleBias;
|
|
#ifdef MESHLET_MESH_MATERIAL_PASS
|
|
bias.ddx_uv = in.ddx_uv;
|
|
bias.ddy_uv = in.ddy_uv;
|
|
#else // MESHLET_MESH_MATERIAL_PASS
|
|
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 TBN = pbr_functions::calculate_tbn_mikktspace(normal, in.world_tangent);
|
|
|
|
normal = pbr_functions::apply_normal_mapping(
|
|
material.flags,
|
|
TBN,
|
|
double_sided,
|
|
is_front,
|
|
Nt,
|
|
);
|
|
|
|
#endif // STANDARD_MATERIAL_NORMAL_MAP
|
|
#endif // VERTEX_TANGENTS
|
|
#endif // VERTEX_UVS
|
|
|
|
out.normal = vec4(normal * 0.5 + vec3(0.5), 1.0);
|
|
} else {
|
|
out.normal = vec4(in.world_normal * 0.5 + vec3(0.5), 1.0);
|
|
}
|
|
#endif // NORMAL_PREPASS
|
|
|
|
#ifdef MOTION_VECTOR_PREPASS
|
|
#ifdef MESHLET_MESH_MATERIAL_PASS
|
|
out.motion_vector = in.motion_vector;
|
|
#else
|
|
out.motion_vector = pbr_prepass_functions::calculate_motion_vector(in.world_position, in.previous_world_position);
|
|
#endif
|
|
#endif
|
|
|
|
return out;
|
|
}
|
|
#else
|
|
@fragment
|
|
fn fragment(in: prepass_io::VertexOutput) {
|
|
pbr_prepass_functions::prepass_alpha_discard(in);
|
|
}
|
|
#endif // PREPASS_FRAGMENT
|