@@ -37,12 +37,19 @@ void BindVertices(Command& cmd,
37
37
cmd.BindVertices (vtx_buffer);
38
38
}
39
39
40
+ Matrix MakeAnchorScale (const Point& anchor, Vector2 scale) {
41
+ return Matrix::MakeTranslation ({anchor.x , anchor.y , 0 }) *
42
+ Matrix::MakeScale (scale) *
43
+ Matrix::MakeTranslation ({-anchor.x , -anchor.y , 0 });
44
+ }
45
+
40
46
std::shared_ptr<Texture> MakeDownsampleSubpass (
41
47
const ContentContext& renderer,
42
48
std::shared_ptr<Texture> input_texture,
43
49
const SamplerDescriptor& sampler_descriptor,
44
50
const Quad& uvs,
45
- const ISize& subpass_size) {
51
+ const ISize& subpass_size,
52
+ const Vector2 padding) {
46
53
ContentContext::SubpassCallback subpass_callback =
47
54
[&](const ContentContext& renderer, RenderPass& pass) {
48
55
HostBuffer& host_buffer = pass.GetTransientsBuffer ();
@@ -58,20 +65,32 @@ std::shared_ptr<Texture> MakeDownsampleSubpass(
58
65
frame_info.texture_sampler_y_coord_scale = 1.0 ;
59
66
frame_info.alpha = 1.0 ;
60
67
68
+ // Insert transparent gutter around the downsampled image so the blur
69
+ // creates a halo effect.
70
+ Vector2 texture_size = Vector2 (input_texture->GetSize ());
71
+ Quad vertices =
72
+ MakeAnchorScale ({0.5 , 0.5 },
73
+ texture_size / (texture_size + padding * 2 ))
74
+ .Transform (
75
+ {Point (0 , 0 ), Point (1 , 0 ), Point (0 , 1 ), Point (1 , 1 )});
76
+
61
77
BindVertices<TextureFillVertexShader>(cmd, host_buffer,
62
78
{
63
- {Point ( 0 , 0 ) , uvs[0 ]},
64
- {Point ( 1 , 0 ) , uvs[1 ]},
65
- {Point ( 0 , 1 ) , uvs[2 ]},
66
- {Point ( 1 , 1 ) , uvs[3 ]},
79
+ {vertices[ 0 ] , uvs[0 ]},
80
+ {vertices[ 1 ] , uvs[1 ]},
81
+ {vertices[ 2 ] , uvs[2 ]},
82
+ {vertices[ 3 ] , uvs[3 ]},
67
83
});
68
84
85
+ SamplerDescriptor linear_sampler_descriptor = sampler_descriptor;
86
+ linear_sampler_descriptor.mag_filter = MinMagFilter::kLinear ;
87
+ linear_sampler_descriptor.min_filter = MinMagFilter::kLinear ;
69
88
TextureFillVertexShader::BindFrameInfo (
70
89
cmd, host_buffer.EmplaceUniform (frame_info));
71
90
TextureFillFragmentShader::BindTextureSampler (
72
91
cmd, input_texture,
73
92
renderer.GetContext ()->GetSamplerLibrary ()->GetSampler (
74
- sampler_descriptor ));
93
+ linear_sampler_descriptor ));
75
94
76
95
pass.AddCommand (std::move (cmd));
77
96
@@ -125,14 +144,6 @@ std::shared_ptr<Texture> MakeBlurSubpass(
125
144
return out_texture;
126
145
}
127
146
128
- // / Given a desired |scalar|, will return the scalar that gets close but leaves
129
- // / |size| in integer sizes.
130
- Vector2 CalculateIntegerScale (Scalar scalar, ISize size) {
131
- ISize new_size (size.width / scalar, size.height / scalar);
132
- return Vector2 (size.width / static_cast <Scalar>(new_size.width ),
133
- size.height / static_cast <Scalar>(new_size.height ));
134
- }
135
-
136
147
// / Calculate how much to scale down the texture depending on the blur radius.
137
148
// / This curve was taken from |DirectionalGaussianBlurFilterContents|.
138
149
Scalar CalculateScale (Scalar radius) {
@@ -200,46 +211,43 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
200
211
}
201
212
202
213
Scalar blur_radius = CalculateBlurRadius (sigma_);
203
- Scalar desired_scale = 1.0 / CalculateScale (blur_radius);
204
- Vector2 downsample =
205
- CalculateIntegerScale (desired_scale, input_snapshot->texture ->GetSize ());
206
-
207
- // TODO(gaaclarke): This isn't taking into account the blur radius to expand
208
- // the rendered size, so blurred objects are clipped. In
209
- // order for that to be implemented correctly we'll need to
210
- // start adjusting the geometry coordinates in the downsample
211
- // step so that there is a border of transparency around it
212
- // before the blur steps.
214
+ Scalar desired_scalar = CalculateScale (blur_radius);
215
+ Vector2 downsample_scalar (desired_scalar, desired_scalar);
216
+ Vector2 padding (ceil (blur_radius), ceil (blur_radius));
217
+
218
+ Vector2 padded_size =
219
+ Vector2 (input_snapshot->texture ->GetSize ()) + 2.0 * padding;
220
+ Vector2 downsampled_size = padded_size * downsample_scalar;
221
+ // TODO(gaaclarke): I don't think we are correctly handling this fractional
222
+ // amount we are throwing away.
213
223
ISize subpass_size =
214
- ISize (input_snapshot->texture ->GetSize ().width / downsample.x ,
215
- input_snapshot->texture ->GetSize ().height / downsample.y );
224
+ ISize (round (downsampled_size.x ), round (downsampled_size.y ));
216
225
217
226
Quad uvs =
218
227
CalculateUVs (inputs[0 ], entity, input_snapshot->texture ->GetSize ());
219
228
220
229
std::shared_ptr<Texture> pass1_out_texture = MakeDownsampleSubpass (
221
230
renderer, input_snapshot->texture , input_snapshot->sampler_descriptor ,
222
- uvs, subpass_size);
231
+ uvs, subpass_size, padding );
223
232
224
- Size pass1_pixel_size (1.0 / pass1_out_texture->GetSize ().width ,
225
- 1.0 / pass1_out_texture->GetSize ().height );
233
+ Vector2 pass1_pixel_size = 1.0 / Vector2 (pass1_out_texture->GetSize ());
226
234
227
235
std::shared_ptr<Texture> pass2_out_texture = MakeBlurSubpass (
228
236
renderer, pass1_out_texture, input_snapshot->sampler_descriptor ,
229
237
GaussianBlurFragmentShader::BlurInfo{
230
- .blur_uv_offset = Point (0.0 , pass1_pixel_size.height ),
231
- .blur_sigma = sigma_ / downsample .y ,
232
- .blur_radius = blur_radius / downsample .y ,
238
+ .blur_uv_offset = Point (0.0 , pass1_pixel_size.y ),
239
+ .blur_sigma = sigma_ * downsample_scalar .y ,
240
+ .blur_radius = blur_radius * downsample_scalar .y ,
233
241
.step_size = 1.0 ,
234
242
});
235
243
236
244
// TODO(gaaclarke): Make this pass reuse the texture from pass1.
237
245
std::shared_ptr<Texture> pass3_out_texture = MakeBlurSubpass (
238
246
renderer, pass2_out_texture, input_snapshot->sampler_descriptor ,
239
247
GaussianBlurFragmentShader::BlurInfo{
240
- .blur_uv_offset = Point (pass1_pixel_size.width , 0.0 ),
241
- .blur_sigma = sigma_ / downsample .x ,
242
- .blur_radius = blur_radius / downsample .x ,
248
+ .blur_uv_offset = Point (pass1_pixel_size.x , 0.0 ),
249
+ .blur_sigma = sigma_ * downsample_scalar .x ,
250
+ .blur_radius = blur_radius * downsample_scalar .x ,
243
251
.step_size = 1.0 ,
244
252
});
245
253
@@ -249,14 +257,10 @@ std::optional<Entity> GaussianBlurFilterContents::RenderFilter(
249
257
return Entity::FromSnapshot (
250
258
Snapshot{
251
259
.texture = pass3_out_texture,
252
- .transform =
253
- entity.GetTransform () *
254
- Matrix::MakeScale (
255
- {input_snapshot->texture ->GetSize ().width /
256
- static_cast <Scalar>(pass1_out_texture->GetSize ().width ),
257
- input_snapshot->texture ->GetSize ().height /
258
- static_cast <Scalar>(pass1_out_texture->GetSize ().height ),
259
- 1.0 }),
260
+ .transform = entity.GetTransform () *
261
+ Matrix::MakeTranslation ({-padding.x , -padding.y , 0 }) *
262
+ Matrix::MakeScale (padded_size /
263
+ Vector2 (pass1_out_texture->GetSize ())),
260
264
.sampler_descriptor = sampler_desc,
261
265
.opacity = input_snapshot->opacity },
262
266
entity.GetBlendMode (), entity.GetClipDepth ());
0 commit comments