@@ -4,6 +4,45 @@ struct Pixel
4
4
splat_xyz:: Point3f
5
5
end
6
6
Pixel () = Pixel (Point3f (0.0f0 ), 0.0f0 , Point3f (0.0f0 ))
7
+
8
+
9
+ function filter_offset (x, discrete_point, inv_filter_radius, filter_table_width)
10
+ fx = abs ((x - discrete_point) * inv_filter_radius * filter_table_width)
11
+ return clamp (u_int32 (ceil (fx)), Int32 (1 ), Int32 (filter_table_width)) # TODO is clipping ok?
12
+ end
13
+
14
+
15
+ function generate_filter_table (filter)
16
+ filter_table_width = 16
17
+ filter_table = Matrix {Float32} (undef, filter_table_width, filter_table_width)
18
+ r = filter. radius ./ filter_table_width
19
+ for y in 0 : filter_table_width- 1 , x in 0 : filter_table_width- 1
20
+ p = Point2f ((x + 0.5f0 ) * r[1 ], (y + 0.5f0 ) * r[2 ])
21
+ filter_table[y+ 1 , x+ 1 ] = filter (p)
22
+ end
23
+
24
+ point = Point2f (filter_table_width)
25
+ # Compute sample's raster bounds.
26
+ discrete_point = point .- 0.5f0
27
+ # Compute sample radius around point
28
+ p0 = ceil .(Int, discrete_point .- filter. radius)
29
+ p1 = floor .(Int, discrete_point .+ filter. radius) .+ 1
30
+ # Make sure we're inbounds
31
+ inv_radius = 1.0f0 ./ filter. radius
32
+ # Precompute x & y filter offsets.
33
+ offsets_x = filter_offsets (p0[1 ], p1[1 ], discrete_point[1 ], inv_radius[1 ], filter_table_width)
34
+ offsets_y = filter_offsets (p0[2 ], p1[2 ], discrete_point[2 ], inv_radius[2 ], filter_table_width)
35
+ # Loop over filter support & add sample to pixel array.
36
+ xrange = p0[1 ]: p1[1 ]
37
+ yrange = p0[2 ]: p1[2 ]
38
+ weights = zeros (Float32, length (xrange), length (yrange))
39
+ for i in 1 : length (xrange), j in 1 : length (yrange)
40
+ w = filter_table[offsets_y[j], offsets_x[i]]
41
+ weights[i, j] = w
42
+ end
43
+ return weights
44
+ end
45
+
7
46
struct Film{Pixels<: AbstractMatrix{Pixel} }
8
47
resolution:: Point2f
9
48
"""
@@ -92,153 +131,68 @@ struct FilmTilePixel{S<:Spectrum}
92
131
end
93
132
FilmTilePixel () = FilmTilePixel (RGBSpectrum (), 0f0 )
94
133
95
- struct FilmTile{Pixels<: AbstractMatrix{<:FilmTilePixel} }
96
- """
97
- Bounds should start from 1 not 0.
98
- """
99
- bounds:: Bounds2
100
- filter_radius:: Point2f
101
- inv_filter_radius:: Point2f
102
- filter_table_width:: Int32
103
- pixels:: Pixels
104
- end
105
134
106
- function FilmTile (
107
- bounds:: Bounds2 , filter_radius:: Point2f ,
108
- filter_table_width:: Int32 ,
109
- )
110
- # Include some padding for over rounding (since we re-use the tiles)
111
- tile_res = (Int32 .(inclusive_sides (bounds))) .+ 2
112
- contrib_sum = fill (RGBSpectrum (), tile_res[2 ], tile_res[1 ])
113
- filter_weight_sum = fill (0.0f0 , tile_res[2 ], tile_res[1 ])
114
- pixels = StructArray {FilmTilePixel{RGBSpectrum}} ((contrib_sum, filter_weight_sum))
115
- FilmTile {typeof(pixels)} (
116
- bounds, filter_radius, 1.0f0 ./ filter_radius,
117
- filter_table_width,
118
- pixels,
119
- )
120
- end
121
135
122
136
"""
123
- Bounds should start from 1 not 0 .
137
+ Point in (x, y) format .
124
138
"""
125
- function FilmTile (f:: Film , sample_bounds:: Bounds2 , radius)
126
- p0 = ceil .(sample_bounds. p_min .- 0.5f0 .- radius)
127
- p1 = floor .(sample_bounds. p_max .- 0.5f0 .+ radius) .+ 1f0
128
- tile_bounds = Bounds2 (p0, p1) ∩ f. crop_bounds
129
- FilmTile (tile_bounds, radius, f. filter_table_width)
130
- end
131
-
132
- function reset! (tile:: FilmTile )
133
-
134
- tile. pixels. contrib_sum .= (RGBSpectrum (0f0 ),)
135
- tile. pixels. filter_weight_sum .= 0f0
136
- end
137
-
138
- function update_bounds! (f:: Film , tile:: FilmTile , sample_bounds:: Bounds2 )
139
- reset! (tile)
140
- radius = tile. filter_radius
141
- p0 = ceil .(sample_bounds. p_min .- 0.5f0 .- radius)
142
- p1 = floor .(sample_bounds. p_max .- 0.5f0 .+ radius) .+ 1.0f0
143
- bounds = Bounds2 (p0, p1) ∩ f. crop_bounds
144
- tile_res = (Int32 .(inclusive_sides (bounds)))
145
- @assert all (reverse (tile_res) .<= size (tile. pixels)) " $(reverse (tile_res)) != $(size (tile. pixels)) $(sample_bounds) "
146
- FilmTile (bounds, radius, tile. inv_filter_radius, tile. filter_table_width, tile. pixels)
147
- end
148
-
149
- function filter_offset! (offsets, start, stop, discrete_point, inv_filter_radius, filter_table_width)
150
- @inbounds for (i, x) in enumerate (Int (start): Int (stop))
151
- fx = abs ((x - discrete_point) * inv_filter_radius * filter_table_width)
152
- offsets[i] = clamp (ceil (fx), 1 , filter_table_width) # TODO is clipping ok?
139
+ @inline function get_pixel_index (crop_bounds, p:: Point2 )
140
+ i1, i2 = u_int32 .((p .- crop_bounds. p_min .+ 1.0f0 ))
141
+ return CartesianIndex (i1, i2)
142
+ end
143
+
144
+ @inline function merge_film_tile! (f:: AbstractMatrix{Pixel} , crop_bounds:: Bounds2 , ft:: AbstractMatrix{FilmTilePixel} , tile:: Bounds2 , tile_col:: Int32 )
145
+ ft_contrib_sum = ft. contrib_sum
146
+ ft_filter_weight_sum = ft. filter_weight_sum
147
+ f_xyz = f. xyz
148
+ f_filter_weight_sum = f. filter_weight_sum
149
+ linear = Int32 (1 )
150
+ @inbounds for pixel in tile
151
+ f_idx = get_pixel_index (crop_bounds, pixel)
152
+ f_xyz[f_idx] += to_XYZ (ft_contrib_sum[linear, tile_col])
153
+ f_filter_weight_sum[f_idx] += ft_filter_weight_sum[linear, tile_col]
154
+ linear += Int32 (1 )
153
155
end
156
+ return
154
157
end
155
158
156
- @inline function filter_offset (x, discrete_point, inv_filter_radius, filter_table_width)
157
- fx = abs ((x - discrete_point) * inv_filter_radius * filter_table_width)
158
- return clamp (u_int32 (ceil (fx)), Int32 (1 ), Int32 (filter_table_width)) # TODO is clipping ok?
159
- end
160
-
161
- function filter_offsets (start, stop, discrete_point, inv_filter_radius, filter_table_width):: NTuple{8, Int32}
162
- range = Int32 (start): Int32 (stop)
163
- return ntuple (8 ) do i
164
- if i <= length (range)
165
- filter_offset (range[i], discrete_point, inv_filter_radius, filter_table_width):: Int32
166
- else
167
- Int32 (0 )
168
- end
169
- end
159
+ @inline function get_tile_index (bounds:: Bounds2 , p:: Point2 )
160
+ j, i = u_int32 .((p .- bounds. p_min .+ 1.0f0 ))
161
+ ncols = u_int32 (inclusive_sides (bounds)[1 ])
162
+ return (i - Int32 (1 )) * ncols + j
170
163
end
171
164
172
- """
173
- Add sample contribution to the film tile.
174
-
175
- - `point::Point2f`:
176
- should start from 1 not 0.
177
- And is relative to the film, not the film tile.
178
- """
179
- function add_sample! (
180
- film:: Film , t:: FilmTile , point:: Point2f , spectrum:: S ,
181
- sample_weight:: Float32 = 1f0 ,
182
- ) where S<: Spectrum
183
-
165
+ @inline function add_sample! (
166
+ tiles:: AbstractMatrix{FilmTilePixel} , tile:: Bounds2 , tile_column:: Int32 , point:: Point2f , spectrum:: RGBSpectrum ,
167
+ filter_table, filter_radius:: Point2f , sample_weight:: Float32 = 1.0f0 ,
168
+ )
184
169
# Compute sample's raster bounds.
185
170
discrete_point = point .- 0.5f0
186
- p0 = ceil .(Int32, discrete_point .- t. filter_radius)
187
- p1 = floor .(Int32, discrete_point .+ t. filter_radius) .+ Int32 (1 )
188
- p0 = Int32 .(max .(p0, max .(t. bounds. p_min, Point2 {Int32} (1 ))))
189
- p1 = Int32 .(min .(p1, t. bounds. p_max))
190
- # Precompute x & y filter offsets.
191
- offsets_x = filter_offsets (p0[1 ], p1[1 ], discrete_point[1 ], t. inv_filter_radius[1 ], t. filter_table_width)
192
- offsets_y = filter_offsets (p0[2 ], p1[2 ], discrete_point[2 ], t. inv_filter_radius[2 ], t. filter_table_width)
171
+ # Compute sample radius around point
172
+ p0 = u_int32 .(ceil .(discrete_point .- filter_radius))
173
+ p1 = u_int32 .(floor .(discrete_point .+ filter_radius)) .+ Int32 (1 )
174
+ # Make sure we're inbounds
175
+ pmin = u_int32 .(tile. p_min)
176
+ pmax = u_int32 .(tile. p_max)
177
+ p0 = max .(p0, max .(pmin, Point2 {Int32} (1 ))):: Point2{Int32}
178
+ p1 = min .(p1, pmax):: Point2{Int32}
193
179
# Loop over filter support & add sample to pixel array.
194
- pixels = t. pixels
195
- contrib_sum = pixels. contrib_sum
196
- filter_weight_sum = pixels. filter_weight_sum
197
- filter_table = film. filter_table
198
- @inbounds for (j, y) in enumerate (Int (p0[2 ]): Int (p1[2 ])), (i, x) in enumerate (Int (p0[1 ]): Int (p1[1 ]))
199
- w = filter_table[offsets_y[j], offsets_x[i]]
200
- @real_assert sample_weight <= 1
201
- @real_assert w <= 1
202
- idx = get_pixel_index (t, Point2 (x, y))
203
- contrib_sum[idx] += spectrum * sample_weight * w
204
- filter_weight_sum[idx] += w
180
+ contrib_sum = tiles. contrib_sum
181
+ filter_weight_sum = tiles. filter_weight_sum
182
+ xrange = p0[1 ]: p1[1 ]
183
+ yrange = p0[2 ]: p1[2 ]
184
+ xn = length (xrange) % Int32
185
+ yn = length (yrange) % Int32
186
+ @inbounds for i in Int32 (1 ): xn, j in Int32 (1 ): yn
187
+ x = xrange[i]
188
+ y = yrange[j]
189
+ w = filter_table[i, j]
190
+ idx = get_tile_index (tile, Point2 (x, y))
191
+ contrib_sum[idx, tile_column] += spectrum * sample_weight * w
192
+ filter_weight_sum[idx, tile_column] += w
205
193
end
206
194
end
207
195
208
- """
209
- Point in (x, y) format.
210
- """
211
- @inline function get_pixel_index (t:: FilmTile , p:: Point2 )
212
- i1, i2 = u_int32 .((p .- t. bounds. p_min .+ 1f0 ))
213
- return CartesianIndex (i2, i1)
214
- end
215
-
216
- """
217
- Point in (x, y) format.
218
- """
219
- @inline function get_pixel_index (f:: Film , p:: Point2 )
220
- i1, i2 = u_int32 .((p .- f. crop_bounds. p_min .+ 1f0 ))
221
- return CartesianIndex (i2, i1)
222
- end
223
-
224
- function merge_film_tile! (f:: Film , ft:: FilmTile )
225
- x_range = Int (ft. bounds. p_min[1 ]): Int (ft. bounds. p_max[1 ])
226
- y_range = Int (ft. bounds. p_min[2 ]): Int (ft. bounds. p_max[2 ])
227
- ft_contrib_sum = ft. pixels. contrib_sum
228
- ft_filter_weight_sum = ft. pixels. filter_weight_sum
229
- f_xyz = f. pixels. xyz
230
- f_filter_weight_sum = f. pixels. filter_weight_sum
231
-
232
- @inbounds for y in y_range, x in x_range
233
- pixel = Point2 {Int32} (x, y)
234
- ft_idx = get_pixel_index (ft, pixel)
235
- f_idx = get_pixel_index (f, pixel)
236
- f_xyz[f_idx] += to_XYZ (ft_contrib_sum[ft_idx])
237
- f_filter_weight_sum[f_idx] += ft_filter_weight_sum[ft_idx]
238
- end
239
- end
240
-
241
-
242
196
function set_image! (f:: Film , spectrum:: Matrix{S} ) where {S<: Spectrum }
243
197
@real_assert size (f. pixels) == size (spectrum)
244
198
f. pixels. xyz .= to_XYZ .(spectrum)
0 commit comments