-
Notifications
You must be signed in to change notification settings - Fork 30.1k
Description
At some point content reaches a threshold where it will shimmer under a blur if the sigma is large enough.
In the below test that inflection point is somewhere between sigma 50 and 60. The differences between sigma 50 and sigma 60 is that the scalar drops from 1/2^4 to 1/2^5. We can't clamp the scalar to 1/2^4 because then our blur radius would get too large for the kernel shader. We could expand the size of the kernel shader, and we could also do the sample_size/2+lerp hack to reduce our kernel size.
I suspect this ratio isn't a hard rule either, that the limit we want will depend on the size of the texture being blurred. At a certain point scaling something down to a handful of pixels is going to look bad.
Note: the videos below aren't capturing at high enough quality to represent the quality you see on the screen, but the motion of the blur can be seen
Engine version: 1312954
sigma 50
Untitled.mp4
sigma 60
Untitled2.mp4
reproduction code
TEST_P(AiksTest, GaussianBlurAnimatedBackdrop) {
// This test is for checking out how stable rendering is when content is
// translated underneath a blur. Animating under a blur can cause
// *shimmering* to happen as a result of pixel alignment.
// See also: https://github.com/flutter/flutter/issues/140193
auto boston = std::make_shared<Image>(
CreateTextureForFixture("boston.jpg", /*enable_mipmapping=*/true));
ASSERT_TRUE(boston);
int64_t count = 0;
Scalar sigma = 20.0;
Scalar freq = 0.1;
Scalar amp = 50.0;
auto callback = [&](AiksContext& renderer) -> std::optional<Picture> {
ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
{
ImGui::SliderFloat("Sigma", &sigma, 0, 500);
ImGui::SliderFloat("Frequency", &freq, 0.01, 2.0);
ImGui::SliderFloat("Amplitude", &, 1, 100);
}
ImGui::End();
Canvas canvas;
canvas.Scale(GetContentScale());
Scalar y = amp * sin(freq * 2.0 * M_PI * count / 60);
canvas.DrawImage(boston,
Point(1024 / 2 - boston->GetSize().width / 2,
(768 / 2 - boston->GetSize().height / 2) + y),
{});
canvas.ClipRect(Rect::MakeLTRB(100, 100, 900, 700));
canvas.SaveLayer({.blend_mode = BlendMode::kSource}, std::nullopt,
ImageFilter::MakeBlur(Sigma(sigma), Sigma(sigma),
FilterContents::BlurStyle::kNormal,
Entity::TileMode::kClamp));
count += 1;
return canvas.EndRecordingAsPicture();
};
ASSERT_TRUE(OpenPlaygroundHere(callback));
}