37 secondary_blur_sigma_ = sigma;
42 if (blur_direction_.
IsZero()) {
43 blur_direction_ =
Vector2(0, 1);
48 blur_style_ = blur_style;
53 tile_mode_ = tile_mode;
57 bool is_second_pass) {
58 is_second_pass_ = is_second_pass;
61 std::optional<Entity> DirectionalGaussianBlurFilterContents::RenderFilter(
65 const Matrix& effect_transform,
67 const std::optional<Rect>& coverage_hint)
const {
80 auto radius = std::min(Radius{blur_sigma_}.radius, 500.0f);
83 auto transformed_blur_radius =
86 auto transformed_blur_radius_length = transformed_blur_radius.GetLength();
90 std::optional<Rect> expanded_coverage_hint;
91 if (coverage_hint.has_value()) {
93 Size(transformed_blur_radius_length, transformed_blur_radius_length)
95 expanded_coverage_hint =
96 is_second_pass_ ? coverage_hint
97 :
Rect(coverage_hint.value().origin - r,
98 Size(coverage_hint.value().size + r * 2));
100 auto input_snapshot = inputs[0]->GetSnapshot(
"GaussianBlur", renderer, entity,
101 expanded_coverage_hint);
102 if (!input_snapshot.has_value()) {
114 if (transformed_blur_radius_length < .5) {
123 transformed_blur_radius.Normalize().AngleTo({1, 0}));
127 auto pass_transform = texture_rotate * input_snapshot->transform;
133 auto pass_texture_rect =
Rect::MakeSize(input_snapshot->texture->GetSize())
135 pass_texture_rect.
origin.
x -= transformed_blur_radius_length;
136 pass_texture_rect.size.width += transformed_blur_radius_length * 2;
140 auto pass_uv_project = [&texture_rotate,
141 &pass_texture_rect](Snapshot& input) {
143 (texture_rotate * input.transform).Invert();
144 return pass_texture_rect.GetTransformedPoints(uv_matrix);
147 auto input_uvs = pass_uv_project(input_snapshot.value());
156 auto& host_buffer = pass.GetTransientsBuffer();
158 VertexBufferBuilder<VS::PerVertexData> vtx_builder;
159 vtx_builder.AddVertices({
160 {
Point(0, 0), input_uvs[0]},
161 {
Point(1, 0), input_uvs[1]},
162 {
Point(1, 1), input_uvs[3]},
163 {
Point(0, 0), input_uvs[0]},
164 {
Point(1, 1), input_uvs[3]},
165 {
Point(0, 1), input_uvs[2]},
167 auto vtx_buffer = vtx_builder.CreateVertexBuffer(host_buffer);
169 VS::FrameInfo frame_info;
171 frame_info.texture_sampler_y_coord_scale =
172 input_snapshot->texture->GetYCoordScale();
174 FS::BlurInfo frag_info;
175 auto r = Radius{transformed_blur_radius_length};
176 frag_info.blur_sigma = Sigma{r}.sigma;
177 frag_info.blur_radius = std::round(r.radius);
180 frag_info.blur_uv_offset =
181 pass_transform.Invert().TransformDirection(
Vector2(1, 0)).Normalize() /
182 Point(input_snapshot->GetCoverage().value().size);
186 transformed_blur_radius_length));
187 cmd.BindVertices(vtx_buffer);
191 auto input_descriptor = input_snapshot->sampler_descriptor;
192 switch (tile_mode_) {
194 if (renderer.GetDeviceCapabilities()
195 .SupportsDecalSamplerAddressMode()) {
216 bool has_decal_specialization =
218 !renderer.GetDeviceCapabilities().SupportsDecalSamplerAddressMode();
220 if (has_decal_specialization) {
221 cmd.pipeline = renderer.GetGaussianBlurDecalPipeline(options);
223 cmd.pipeline = renderer.GetGaussianBlurPipeline(options);
226 FS::BindTextureSampler(
227 cmd, input_snapshot->texture,
228 renderer.GetContext()->GetSamplerLibrary()->GetSampler(
230 VS::BindFrameInfo(cmd, host_buffer.EmplaceUniform(frame_info));
231 FS::BindBlurInfo(cmd, host_buffer.EmplaceUniform(frag_info));
233 return pass.AddCommand(std::move(cmd));
237 auto scale_curve = [](
Scalar radius) {
238 constexpr
Scalar decay = 4.0;
239 constexpr
Scalar limit = 0.95;
241 std::min(1.0, decay / (std::max(1.0f, radius) + decay - 1.0));
242 return (curve - 1) * limit + 1;
245 scale.x = scale_curve(transformed_blur_radius_length);
247 Scalar y_radius = std::abs(pass_transform.GetDirectionScale(
Vector2(
248 0, !is_second_pass_ ? 1 : Radius{secondary_blur_sigma_}.radius)));
249 scale.y = scale_curve(y_radius);
252 Vector2 scaled_size = pass_texture_rect.size * scale;
253 ISize floored_size =
ISize(scaled_size.x, scaled_size.y);
255 auto out_texture = renderer.MakeSubpass(
"Directional Gaussian Blur Filter",
256 floored_size, subpass_callback);
262 SamplerDescriptor sampler_desc;
269 Snapshot{.texture = out_texture,
270 .transform = texture_rotate.Invert() *
273 (scaled_size / floored_size)),
274 .sampler_descriptor = sampler_desc,
275 .opacity = input_snapshot->opacity},
282 const Matrix& effect_transform)
const {
283 if (inputs.empty()) {
287 auto coverage = inputs[0]->GetCoverage(entity);
288 if (!coverage.has_value()) {
292 auto transform = inputs[0]->GetTransform(entity) * effect_transform.
Basis();
293 auto transformed_blur_vector =
296 auto extent = coverage->
size + transformed_blur_vector * 2;
297 return Rect(coverage->
origin - transformed_blur_vector,
298 Size(extent.x, extent.y));