Skip to content

Commit 3d4d5fd

Browse files
bderoloic-sharma
authored andcommitted
[Impeller] RRect blur improvements (flutter#38417)
1 parent c324d04 commit 3d4d5fd

File tree

4 files changed

+19
-14
lines changed

4 files changed

+19
-14
lines changed

impeller/compiler/shader_lib/impeller/constants.glsl

+3
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ const float kSqrtTwoPi = 2.50662827463;
1616
// sqrt(2) / 2 == 1 / sqrt(2)
1717
const float kHalfSqrtTwo = 0.70710678118;
1818

19+
// sqrt(3)
20+
const float kSqrtThree = 1.73205080757;
21+
1922
#endif

impeller/compiler/shader_lib/impeller/gaussian.glsl

+11-9
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,23 @@ vec2 IPVec2Erf(vec2 x) {
2929
return sign(x) * (1 - 1 / (b * b * b * b));
3030
}
3131

32-
/// Indefinite integral of the Gaussian function (with constant range 0->1).
32+
/// The indefinite integral of the Gaussian function.
33+
/// Uses a very close approximation of Erf.
3334
float IPGaussianIntegral(float x, float sigma) {
3435
// ( 1 + erf( x * (sqrt(2) / (2 * sigma) ) ) / 2
35-
// Because this sigmoid is always > 1, we remap it (n * 1.07 - 0.07)
36-
// so that it always fades to zero before it reaches the blur radius.
37-
return 0.535 * IPErf(x * (kHalfSqrtTwo / sigma)) + 0.465;
36+
return (1 + IPErf(x * (kHalfSqrtTwo / sigma))) * 0.5;
3837
}
3938

40-
/// Vec2 variation for the indefinite integral of the Gaussian function (with
41-
/// constant range 0->1).
39+
/// Vec2 variation for the indefinite integral of the Gaussian function.
40+
/// Uses a very close approximation of Erf.
4241
vec2 IPVec2GaussianIntegral(vec2 x, float sigma) {
4342
// ( 1 + erf( x * (sqrt(2) / (2 * sigma) ) ) / 2
44-
// Because this sigmoid is always > 1, we remap it (n * 1.07 - 0.07)
45-
// so that it always fades to zero before it reaches the blur radius.
46-
return 0.535 * IPVec2Erf(x * (kHalfSqrtTwo / sigma)) + 0.465;
43+
return (1 + IPVec2Erf(x * (kHalfSqrtTwo / sigma))) * 0.5;
44+
}
45+
46+
/// Simpler (but less accurate) approximation of the Gaussian integral.
47+
vec2 IPVec2FastGaussianIntegral(vec2 x, float sigma) {
48+
return 1 / (1 + exp(-kSqrtThree / sigma * x));
4749
}
4850

4951
/// Simple logistic sigmoid with a domain of [-1, 1] and range of [0, 1].

impeller/entity/contents/rrect_shadow_contents.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ std::optional<Rect> RRectShadowContents::GetCoverage(
3939
return std::nullopt;
4040
}
4141

42-
Scalar radius = Radius{sigma_}.radius;
42+
Scalar radius = sigma_.sigma * 2;
4343

4444
auto ltrb = rect_->GetLTRB();
4545
Rect bounds = Rect::MakeLTRB(ltrb[0] - radius, ltrb[1] - radius,
@@ -59,7 +59,7 @@ bool RRectShadowContents::Render(const ContentContext& renderer,
5959

6060
VertexBufferBuilder<VS::PerVertexData> vtx_builder;
6161

62-
auto blur_radius = Radius{sigma_}.radius;
62+
auto blur_radius = sigma_.sigma * 2;
6363
auto positive_rect = rect_->GetPositive();
6464
{
6565
auto left = -blur_radius;

impeller/entity/shaders/rrect_blur.frag

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ in vec2 v_position;
1717

1818
out vec4 frag_color;
1919

20-
const int kSampleCount = 5;
20+
const int kSampleCount = 4;
2121

2222
float RRectDistance(vec2 sample_position, vec2 half_size) {
2323
vec2 space = abs(sample_position) - half_size + frag_info.corner_radius;
@@ -37,8 +37,8 @@ float RRectShadowX(vec2 sample_position, vec2 half_size) {
3737
sqrt(max(0, frag_info.corner_radius * frag_info.corner_radius -
3838
space * space));
3939

40-
// Map the linear distance field to the analytical Gaussian integral.
41-
vec2 integral = IPVec2GaussianIntegral(
40+
// Map the linear distance field to the approximate Gaussian integral.
41+
vec2 integral = IPVec2FastGaussianIntegral(
4242
sample_position.x + vec2(-rrect_distance, rrect_distance),
4343
frag_info.blur_sigma);
4444
return integral.y - integral.x;

0 commit comments

Comments
 (0)