|
18 | 18 | #import bevy_core_pipeline::fullscreen_vertex_shader::FullscreenVertexOutput |
19 | 19 | #import bevy_pbr::mesh_view_bindings::view |
20 | 20 | #import bevy_pbr::view_transformations::depth_ndc_to_view_z |
| 21 | +#import bevy_post_process::gaussian_blur::gaussian_blur |
21 | 22 | #import bevy_render::view::View |
22 | 23 |
|
23 | 24 | // Parameters that control the depth of field effect. See |
@@ -136,69 +137,6 @@ fn calculate_circle_of_confusion(in_frag_coord: vec4<f32>) -> f32 { |
136 | 137 | return clamp(candidate_coc * framebuffer_size.y, 0.0, max_coc_diameter); |
137 | 138 | } |
138 | 139 |
|
139 | | -// Performs a single direction of the separable Gaussian blur kernel. |
140 | | -// |
141 | | -// * `frag_coord` is the screen-space pixel coordinate of the fragment (i.e. the |
142 | | -// `position` input to the fragment). |
143 | | -// |
144 | | -// * `coc` is the diameter (not the radius) of the circle of confusion for this |
145 | | -// fragment. |
146 | | -// |
147 | | -// * `frag_offset` is the vector, in screen-space units, from one sample to the |
148 | | -// next. For a horizontal blur this will be `vec2(1.0, 0.0)`; for a vertical |
149 | | -// blur this will be `vec2(0.0, 1.0)`. |
150 | | -// |
151 | | -// Returns the resulting color of the fragment. |
152 | | -fn gaussian_blur(frag_coord: vec4<f32>, coc: f32, frag_offset: vec2<f32>) -> vec4<f32> { |
153 | | - // Usually σ (the standard deviation) is half the radius, and the radius is |
154 | | - // half the CoC. So we multiply by 0.25. |
155 | | - let sigma = coc * 0.25; |
156 | | - |
157 | | - // 1.5σ is a good, somewhat aggressive default for support—the number of |
158 | | - // texels on each side of the center that we process. |
159 | | - let support = i32(ceil(sigma * 1.5)); |
160 | | - let uv = frag_coord.xy / vec2<f32>(textureDimensions(color_texture_a)); |
161 | | - let offset = frag_offset / vec2<f32>(textureDimensions(color_texture_a)); |
162 | | - |
163 | | - // The probability density function of the Gaussian blur is (up to constant factors) `exp(-1 / 2σ² * |
164 | | - // x²). We precalculate the constant factor here to avoid having to |
165 | | - // calculate it in the inner loop. |
166 | | - let exp_factor = -1.0 / (2.0 * sigma * sigma); |
167 | | - |
168 | | - // Accumulate samples on both sides of the current texel. Go two at a time, |
169 | | - // taking advantage of bilinear filtering. |
170 | | - var sum = textureSampleLevel(color_texture_a, color_texture_sampler, uv, 0.0).rgb; |
171 | | - var weight_sum = 1.0; |
172 | | - for (var i = 1; i <= support; i += 2) { |
173 | | - // This is a well-known trick to reduce the number of needed texture |
174 | | - // samples by a factor of two. We seek to accumulate two adjacent |
175 | | - // samples c₀ and c₁ with weights w₀ and w₁ respectively, with a single |
176 | | - // texture sample at a carefully chosen location. Observe that: |
177 | | - // |
178 | | - // k ⋅ lerp(c₀, c₁, t) = w₀⋅c₀ + w₁⋅c₁ |
179 | | - // |
180 | | - // w₁ |
181 | | - // if k = w₀ + w₁ and t = ─────── |
182 | | - // w₀ + w₁ |
183 | | - // |
184 | | - // Therefore, if we sample at a distance of t = w₁ / (w₀ + w₁) texels in |
185 | | - // between the two texel centers and scale by k = w₀ + w₁ afterward, we |
186 | | - // effectively evaluate w₀⋅c₀ + w₁⋅c₁ with a single texture lookup. |
187 | | - let w0 = exp(exp_factor * f32(i) * f32(i)); |
188 | | - let w1 = exp(exp_factor * f32(i + 1) * f32(i + 1)); |
189 | | - let uv_offset = offset * (f32(i) + w1 / (w0 + w1)); |
190 | | - let weight = w0 + w1; |
191 | | - |
192 | | - sum += ( |
193 | | - textureSampleLevel(color_texture_a, color_texture_sampler, uv + uv_offset, 0.0).rgb + |
194 | | - textureSampleLevel(color_texture_a, color_texture_sampler, uv - uv_offset, 0.0).rgb |
195 | | - ) * weight; |
196 | | - weight_sum += weight * 2.0; |
197 | | - } |
198 | | - |
199 | | - return vec4(sum / weight_sum, 1.0); |
200 | | -} |
201 | | - |
202 | 140 | // Performs a box blur in a single direction, sampling `color_texture_a`. |
203 | 141 | // |
204 | 142 | // * `frag_coord` is the screen-space pixel coordinate of the fragment (i.e. the |
@@ -255,14 +193,14 @@ fn box_blur_b(frag_coord: vec4<f32>, coc: f32, frag_offset: vec2<f32>) -> vec4<f |
255 | 193 | @fragment |
256 | 194 | fn gaussian_horizontal(in: FullscreenVertexOutput) -> @location(0) vec4<f32> { |
257 | 195 | let coc = calculate_circle_of_confusion(in.position); |
258 | | - return gaussian_blur(in.position, coc, vec2(1.0, 0.0)); |
| 196 | + return gaussian_blur(color_texture_a, color_texture_sampler, in.position, coc, vec2(1.0, 0.0)); |
259 | 197 | } |
260 | 198 |
|
261 | 199 | // Calculates the vertical component of the separable Gaussian blur. |
262 | 200 | @fragment |
263 | 201 | fn gaussian_vertical(in: FullscreenVertexOutput) -> @location(0) vec4<f32> { |
264 | 202 | let coc = calculate_circle_of_confusion(in.position); |
265 | | - return gaussian_blur(in.position, coc, vec2(0.0, 1.0)); |
| 203 | + return gaussian_blur(color_texture_a, color_texture_sampler, in.position, coc, vec2(0.0, 1.0)); |
266 | 204 | } |
267 | 205 |
|
268 | 206 | // Calculates the vertical and first diagonal components of the separable |
|
0 commit comments