Search across packages, versions, files, declarations, and comments. Use multiple terms to narrow results (AND), and add @vertex, @fragment, or @compute to filter by shader stage.
1import bevy_render::bindless::{bindless_samplers_filtering, bindless_textures_2d};
3import package::render::{
4 pbr_bindings::{depth_map_texture, depth_map_sampler},
5 mesh_bindings::mesh
6};
8@if(BINDLESS)
9import package::render::pbr_bindings::material_indices;
11fn sample_depth_map(uv: vec2<f32>, material_bind_group_slot: u32) -> f32 {
12 // We use `textureSampleLevel` over `textureSample` because the wgpu DX12
13 // backend (Fxc) panics when using "gradient instructions" inside a loop.
14 // It results in the whole loop being unrolled by the shader compiler,
15 // which it can't do because the upper limit of the loop in steep parallax
16 // mapping is a variable set by the user.
17 // The "gradient instructions" comes from `textureSample` computing MIP level
18 // based on UV derivative. With `textureSampleLevel`, we provide ourselves
19 // the MIP level, so no gradient instructions are used, and we can use
20 // sample_depth_map in our loop.
21 // See https://stackoverflow.com/questions/56581141/direct3d11-gradient-instruction-used-in-a-loop-with-varying-iteration-forcing
22 @if(BINDLESS)
23 return textureSampleLevel(
24 bindless_textures_2d[material_indices[material_bind_group_slot].depth_map_texture],
25 bindless_samplers_filtering[material_indices[material_bind_group_slot].depth_map_sampler],
26 uv,
27 0.0
28 ).r;
29 @else
30 return textureSampleLevel(
31 depth_map_texture,
32 depth_map_sampler,
33 uv,
34 0.0
35 ).r;
38/// An implementation of parallax mapping, see https://en.wikipedia.org/wiki/Parallax_mapping
39/// Code derived from: https://web.archive.org/web/20150419215321/http://sunandblackcat.com/tipFullView.php?l=eng&topicid=28
40fn parallaxed_uv(
41 depth_scale: f32,
42 max_layer_count: f32,
43 max_steps: u32,
44 /// The original interpolated uv
45 original_uv: vec2<f32>,
46 /// The vector from the camera to the fragment at the surface in tangent space
47 Vt: vec3<f32>,
48 material_bind_group_slot: u32,
49) -> vec2<f32> {
50 if max_layer_count < 1.0 {
51 return original_uv;
52 }
53 var uv = original_uv;
55 // Steep Parallax Mapping
56 // ======================
57 // Split the depth map into `layer_count` layers.
58 // When Vt hits the surface of the mesh (excluding depth displacement),
59 // if the depth is not below or on surface including depth displacement (textureSample), then
60 // look forward (+= delta_uv) on depth texture according to
61 // Vt and distance between hit surface and depth map surface,
62 // repeat until below the surface.
63 //
64 // Where `layer_count` is interpolated between `1.0` and
65 // `max_layer_count` according to the steepness of Vt.
67 let view_steepness = abs(Vt.z);
68 // We mix with minimum value 1.0 because otherwise,
69 // with 0.0, we get a division by zero in surfaces parallel to viewport,
70 // resulting in a singularity.
71 let layer_count = mix(max_layer_count, 1.0, view_steepness);
72 let layer_depth = 1.0 / layer_count;
73 var delta_uv = depth_scale * layer_depth * Vt.xy * vec2(1.0, -1.0) / view_steepness;
75 var current_layer_depth = 0.0;
76 var texture_depth = sample_depth_map(uv, material_bind_group_slot);
78 // texture_depth > current_layer_depth means the depth map depth is deeper
79 // than the depth the ray would be at this UV offset so the ray has not
80 // intersected the surface
81 for (var i: i32 = 0; texture_depth > current_layer_depth && i <= i32(layer_count); i++) {
82 current_layer_depth += layer_depth;
83 uv += delta_uv;
84 texture_depth = sample_depth_map(uv, material_bind_group_slot);
85 }
87 @if(RELIEF_MAPPING) {
88 // Relief Mapping
89 // ==============
90 // "Refine" the rough result from Steep Parallax Mapping
91 // with a **binary search** between the layer selected by steep parallax
92 // and the next one to find a point closer to the depth map surface.
93 // This reduces the jaggy step artifacts from steep parallax mapping.
95 delta_uv *= 0.5;
96 var delta_depth = 0.5 * layer_depth;
98 uv -= delta_uv;
99 current_layer_depth -= delta_depth;
101 for (var i: u32 = 0u; i < max_steps; i++) {
102 texture_depth = sample_depth_map(uv, material_bind_group_slot);
104 // Halve the deltas for the next step
105 delta_uv *= 0.5;
106 delta_depth *= 0.5;
108 // Step based on whether the current depth is above or below the depth map
109 if (texture_depth > current_layer_depth) {
110 uv += delta_uv;
111 current_layer_depth += delta_depth;
112 } else {
113 uv -= delta_uv;
114 current_layer_depth -= delta_depth;
115 }
116 }
117 } @else {
118 // Parallax Occlusion mapping
119 // ==========================
120 // "Refine" Steep Parallax Mapping by interpolating between the
121 // previous layer's depth and the computed layer depth.
122 // Only requires a single lookup, unlike Relief Mapping, but
123 // may skip small details and result in writhing material artifacts.
124 let previous_uv = uv - delta_uv;
125 let next_depth = texture_depth - current_layer_depth;
126 let previous_depth = sample_depth_map(previous_uv, material_bind_group_slot) -
127 current_layer_depth + layer_depth;
129 let weight = next_depth / (next_depth - previous_depth);
131 uv = mix(uv, previous_uv, weight);
133 current_layer_depth += mix(next_depth, previous_depth, weight);
134 }
136 // Note: `current_layer_depth` is not returned, but may be useful
137 // for light computation later on in future improvements of the pbr shader.
138 return uv;
Contents