Blender V4.3
kernel/light/background.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
7#include "kernel/light/area.h"
9
11
12/* Background Light */
13
15{
16 /* for the following, the CDF values are actually a pair of floats, with the
17 * function value as X and the actual CDF as Y. The last entry's function
18 * value is the CDF total. */
19 int res_x = kernel_data.background.map_res_x;
20 int res_y = kernel_data.background.map_res_y;
21 int cdf_width = res_x + 1;
22
23 /* This is basically std::lower_bound as used by PBRT. */
24 int first = 0;
25 int count = res_y;
26
27 while (count > 0) {
28 int step = count >> 1;
29 int middle = first + step;
30
31 if (kernel_data_fetch(light_background_marginal_cdf, middle).y < rand.y) {
32 first = middle + 1;
33 count -= step + 1;
34 }
35 else
36 count = step;
37 }
38
39 int index_v = max(0, first - 1);
40 kernel_assert(index_v >= 0 && index_v < res_y);
41
42 float2 cdf_v = kernel_data_fetch(light_background_marginal_cdf, index_v);
43 float2 cdf_next_v = kernel_data_fetch(light_background_marginal_cdf, index_v + 1);
44 float2 cdf_last_v = kernel_data_fetch(light_background_marginal_cdf, res_y);
45
46 /* importance-sampled V direction */
47 float dv = inverse_lerp(cdf_v.y, cdf_next_v.y, rand.y);
48 float v = (index_v + dv) / res_y;
49
50 /* This is basically std::lower_bound as used by PBRT. */
51 first = 0;
52 count = res_x;
53 while (count > 0) {
54 int step = count >> 1;
55 int middle = first + step;
56
57 if (kernel_data_fetch(light_background_conditional_cdf, index_v * cdf_width + middle).y <
58 rand.x)
59 {
60 first = middle + 1;
61 count -= step + 1;
62 }
63 else
64 count = step;
65 }
66
67 int index_u = max(0, first - 1);
68 kernel_assert(index_u >= 0 && index_u < res_x);
69
70 float2 cdf_u = kernel_data_fetch(light_background_conditional_cdf,
71 index_v * cdf_width + index_u);
72 float2 cdf_next_u = kernel_data_fetch(light_background_conditional_cdf,
73 index_v * cdf_width + index_u + 1);
74 float2 cdf_last_u = kernel_data_fetch(light_background_conditional_cdf,
75 index_v * cdf_width + res_x);
76
77 /* importance-sampled U direction */
78 float du = inverse_lerp(cdf_u.y, cdf_next_u.y, rand.x);
79 float u = (index_u + du) / res_x;
80
81 /* compute pdf */
82 float sin_theta = sinf(M_PI_F * v);
83 float denom = (M_2PI_F * M_PI_F * sin_theta) * cdf_last_u.x * cdf_last_v.x;
84
85 if (sin_theta == 0.0f || denom == 0.0f)
86 *pdf = 0.0f;
87 else
88 *pdf = (cdf_u.x * cdf_v.x) / denom;
89
90 /* compute direction */
92}
93
94/* TODO(sergey): Same as above, after the release we should consider using
95 * 'noinline' for all devices.
96 */
98{
100 int res_x = kernel_data.background.map_res_x;
101 int res_y = kernel_data.background.map_res_y;
102 int cdf_width = res_x + 1;
103
104 float sin_theta = sinf(uv.y * M_PI_F);
105
106 if (sin_theta == 0.0f)
107 return 0.0f;
108
109 int index_u = clamp(float_to_int(uv.x * res_x), 0, res_x - 1);
110 int index_v = clamp(float_to_int(uv.y * res_y), 0, res_y - 1);
111
112 /* pdfs in V direction */
113 float2 cdf_last_u = kernel_data_fetch(light_background_conditional_cdf,
114 index_v * cdf_width + res_x);
115 float2 cdf_last_v = kernel_data_fetch(light_background_marginal_cdf, res_y);
116
117 float denom = (M_2PI_F * M_PI_F * sin_theta) * cdf_last_u.x * cdf_last_v.x;
118
119 if (denom == 0.0f)
120 return 0.0f;
121
122 /* pdfs in U direction */
123 float2 cdf_u = kernel_data_fetch(light_background_conditional_cdf,
124 index_v * cdf_width + index_u);
125 float2 cdf_v = kernel_data_fetch(light_background_marginal_cdf, index_v);
126
127 return (cdf_u.x * cdf_v.x) / denom;
128}
129
131 KernelGlobals kg, float3 P, int index, ccl_private float3 *lightpos, ccl_private float3 *dir)
132{
133 int portal = kernel_data.integrator.portal_offset + index;
134 const ccl_global KernelLight *klight = &kernel_data_fetch(lights, portal);
135
136 *lightpos = klight->co;
137 *dir = klight->area.dir;
138
139 /* Check whether portal is on the right side. */
140 if (dot(*dir, P - *lightpos) > 1e-4f)
141 return true;
142
143 return false;
144}
145
147 KernelGlobals kg, float3 P, float3 direction, int ignore_portal, ccl_private bool *is_possible)
148{
149 float portal_pdf = 0.0f;
150
151 int num_possible = 0;
152 for (int p = 0; p < kernel_data.integrator.num_portals; p++) {
153 if (p == ignore_portal)
154 continue;
155
156 float3 lightpos, dir;
157 if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
158 continue;
159
160 /* There's a portal that could be sampled from this position. */
161 if (is_possible) {
162 *is_possible = true;
163 }
164 num_possible++;
165
166 int portal = kernel_data.integrator.portal_offset + p;
167 const ccl_global KernelLight *klight = &kernel_data_fetch(lights, portal);
168
169 const float3 axis_u = klight->area.axis_u;
170 const float len_u = klight->area.len_u;
171 const float3 axis_v = klight->area.axis_v;
172 const float len_v = klight->area.len_v;
173 const float3 inv_extent_u = axis_u / len_u;
174 const float3 inv_extent_v = axis_v / len_v;
175
176 bool is_round = (klight->area.invarea < 0.0f);
177
179 direction,
180 1e-4f,
181 FLT_MAX,
182 lightpos,
183 inv_extent_u,
184 inv_extent_v,
185 dir,
186 NULL,
187 NULL,
188 NULL,
189 NULL,
190 is_round))
191 continue;
192
193 if (is_round) {
194 float t;
195 float3 D = normalize_len(lightpos - P, &t);
196 portal_pdf += fabsf(klight->area.invarea) * light_pdf_area_to_solid_angle(dir, -D, t);
197 }
198 else {
199 portal_pdf += area_light_rect_sample(
200 P, &lightpos, axis_u, len_u, axis_v, len_v, zero_float2(), false);
201 }
202 }
203
204 if (ignore_portal >= 0) {
205 /* We have skipped a portal that could be sampled as well. */
206 num_possible++;
207 }
208
209 return (num_possible > 0) ? portal_pdf / num_possible : 0.0f;
210}
211
213{
214 int num_possible_portals = 0;
215 for (int p = 0; p < kernel_data.integrator.num_portals; p++) {
216 float3 lightpos, dir;
217 if (background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
218 num_possible_portals++;
219 }
220 return num_possible_portals;
221}
222
224 float3 P,
225 float2 rand,
226 int num_possible,
227 ccl_private int *sampled_portal,
228 ccl_private float *pdf)
229{
230 /* Pick a portal, then re-normalize rand.y. */
231 rand.y *= num_possible;
232 int portal = (int)rand.y;
233 rand.y -= portal;
234
235 /* TODO(sergey): Some smarter way of finding portal to sample
236 * is welcome.
237 */
238 for (int p = 0; p < kernel_data.integrator.num_portals; p++) {
239 /* Search for the sampled portal. */
240 float3 lightpos, dir;
241 if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir))
242 continue;
243
244 if (portal == 0) {
245 /* p is the portal to be sampled. */
246 int portal = kernel_data.integrator.portal_offset + p;
247 const ccl_global KernelLight *klight = &kernel_data_fetch(lights, portal);
248 const float3 axis_u = klight->area.axis_u;
249 const float3 axis_v = klight->area.axis_v;
250 const float len_u = klight->area.len_u;
251 const float len_v = klight->area.len_v;
252 bool is_round = (klight->area.invarea < 0.0f);
253
254 float3 D;
255 if (is_round) {
256 lightpos += ellipse_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, rand);
257 float t;
258 D = normalize_len(lightpos - P, &t);
259 *pdf = fabsf(klight->area.invarea) * light_pdf_area_to_solid_angle(dir, -D, t);
260 }
261 else {
262 *pdf = area_light_rect_sample(P, &lightpos, axis_u, len_u, axis_v, len_v, rand, true);
263 D = normalize(lightpos - P);
264 }
265
266 *pdf /= num_possible;
267 *sampled_portal = p;
268 return D;
269 }
270
271 portal--;
272 }
273
274 return zero_float3();
275}
276
278 float2 rand,
279 ccl_private float *pdf)
280{
281 const float3 N = float4_to_float3(kernel_data.background.sun);
282 const float angle = kernel_data.background.sun.w;
283 float unused;
284 return sample_uniform_cone(N, one_minus_cos(angle), rand, &unused, pdf);
285}
286
288{
289 const float3 N = float4_to_float3(kernel_data.background.sun);
290 const float angle = kernel_data.background.sun.w;
291 return pdf_uniform_cone(N, D, angle);
292}
293
295 float3 P,
296 float2 rand,
297 ccl_private float *pdf)
298{
299 float portal_method_pdf = kernel_data.background.portal_weight;
300 float sun_method_pdf = kernel_data.background.sun_weight;
301 float map_method_pdf = kernel_data.background.map_weight;
302
303 int num_portals = 0;
304 if (portal_method_pdf > 0.0f) {
305 /* Check if there are portals in the scene which we can sample. */
306 num_portals = background_num_possible_portals(kg, P);
307 if (num_portals == 0) {
308 portal_method_pdf = 0.0f;
309 }
310 }
311
312 float pdf_fac = (portal_method_pdf + sun_method_pdf + map_method_pdf);
313 if (pdf_fac == 0.0f) {
314 /* Use uniform as a fallback if we can't use any strategy. */
315 *pdf = 1.0f / M_4PI_F;
316 return sample_uniform_sphere(rand);
317 }
318
319 pdf_fac = 1.0f / pdf_fac;
320 portal_method_pdf *= pdf_fac;
321 sun_method_pdf *= pdf_fac;
322 map_method_pdf *= pdf_fac;
323
324 /* We have 100% in total and split it between the three categories.
325 * Therefore, we pick portals if rand.x is between 0 and portal_method_pdf,
326 * sun if rand.x is between portal_method_pdf and (portal_method_pdf + sun_method_pdf)
327 * and map if rand.x is between (portal_method_pdf + sun_method_pdf) and 1. */
328 float sun_method_cdf = portal_method_pdf + sun_method_pdf;
329
330 int method = 0;
331 float3 D;
332 if (rand.x < portal_method_pdf) {
333 method = 0;
334 /* Rescale rand.x. */
335 if (portal_method_pdf != 1.0f) {
336 rand.x /= portal_method_pdf;
337 }
338
339 /* Sample a portal. */
340 int portal;
341 D = background_portal_sample(kg, P, rand, num_portals, &portal, pdf);
342 if (num_portals > 1) {
343 /* Ignore the chosen portal, its pdf is already included. */
344 *pdf += background_portal_pdf(kg, P, D, portal, NULL);
345 }
346
347 /* Skip MIS if this is the only method. */
348 if (portal_method_pdf == 1.0f) {
349 return D;
350 }
351 *pdf *= portal_method_pdf;
352 }
353 else if (rand.x < sun_method_cdf) {
354 method = 1;
355 /* Rescale rand.x. */
356 if (sun_method_pdf != 1.0f) {
357 rand.x = (rand.x - portal_method_pdf) / sun_method_pdf;
358 }
359
360 D = background_sun_sample(kg, rand, pdf);
361
362 /* Skip MIS if this is the only method. */
363 if (sun_method_pdf == 1.0f) {
364 return D;
365 }
366 *pdf *= sun_method_pdf;
367 }
368 else {
369 method = 2;
370 /* Rescale rand.x. */
371 if (map_method_pdf != 1.0f) {
372 rand.x = (rand.x - sun_method_cdf) / map_method_pdf;
373 }
374
375 D = background_map_sample(kg, rand, pdf);
376
377 /* Skip MIS if this is the only method. */
378 if (map_method_pdf == 1.0f) {
379 return D;
380 }
381 *pdf *= map_method_pdf;
382 }
383
384 /* MIS weighting. */
385 if (method != 0 && portal_method_pdf != 0.0f) {
386 *pdf += portal_method_pdf * background_portal_pdf(kg, P, D, -1, NULL);
387 }
388 if (method != 1 && sun_method_pdf != 0.0f) {
389 *pdf += sun_method_pdf * background_sun_pdf(kg, D);
390 }
391 if (method != 2 && map_method_pdf != 0.0f) {
392 *pdf += map_method_pdf * background_map_pdf(kg, D);
393 }
394 return D;
395}
396
398{
399 float portal_method_pdf = kernel_data.background.portal_weight;
400 float sun_method_pdf = kernel_data.background.sun_weight;
401 float map_method_pdf = kernel_data.background.map_weight;
402
403 float portal_pdf = 0.0f;
404 /* Portals are a special case here since we need to compute their pdf in order
405 * to find out if we can sample them. */
406 if (portal_method_pdf > 0.0f) {
407 /* Evaluate PDF of sampling this direction by portal sampling. */
408 bool is_possible = false;
409 portal_pdf = background_portal_pdf(kg, P, direction, -1, &is_possible);
410 if (!is_possible) {
411 /* Portal sampling is not possible here because all portals point to the wrong side.
412 * If other methods can be used instead, do so, otherwise uniform sampling is used as a
413 * fallback. */
414 portal_method_pdf = 0.0f;
415 }
416 }
417
418 float pdf_fac = (portal_method_pdf + sun_method_pdf + map_method_pdf);
419 if (pdf_fac == 0.0f) {
420 /* Use uniform as a fallback if we can't use any strategy. */
421 return 1.0f / M_4PI_F;
422 }
423
424 pdf_fac = 1.0f / pdf_fac;
425 portal_method_pdf *= pdf_fac;
426 sun_method_pdf *= pdf_fac;
427 map_method_pdf *= pdf_fac;
428
429 float pdf = portal_pdf * portal_method_pdf;
430 if (sun_method_pdf != 0.0f) {
431 pdf += background_sun_pdf(kg, direction) * sun_method_pdf;
432 }
433 if (map_method_pdf != 0.0f) {
434 pdf += background_map_pdf(kg, direction) * map_method_pdf;
435 }
436
437 return pdf;
438}
439
440template<bool in_volume_segment>
442 const float t,
443 ccl_private float &cos_theta_u,
444 ccl_private float2 &distance,
445 ccl_private float3 &point_to_centroid,
446 ccl_private float &theta_d)
447{
448 if (in_volume_segment) {
449 if (t == FLT_MAX) {
450 /* In world volume, distant light has no contribution. */
451 return false;
452 }
453 theta_d = t;
454 }
455
456 /* Cover the whole sphere */
457 cos_theta_u = -1.0f;
458
459 distance = make_float2(1.0f, 1.0f);
460 point_to_centroid = -centroid;
461
462 return true;
463}
464
#define D
CCL_NAMESPACE_BEGIN ccl_device_inline float area_light_rect_sample(float3 P, ccl_private float3 *light_p, const float3 axis_u, const float len_u, const float3 axis_v, const float len_v, const float2 rand, bool sample_coord)
Definition area.h:17
ATTR_WARN_UNUSED_RESULT const BMVert * v
ccl_device_inline float sin_theta(const float3 w)
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
ccl_device float3 equirectangular_to_direction(float u, float v)
ccl_device float2 direction_to_equirectangular(float3 dir)
#define kernel_assert(cond)
#define kernel_data
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
#define ccl_device_forceinline
#define sinf(x)
#define ccl_device
#define ccl_private
#define ccl_device_inline
#define ccl_global
#define CCL_NAMESPACE_END
#define NULL
ccl_device_forceinline float2 make_float2(const float x, const float y)
#define fabsf(x)
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
int count
ccl_device_inline float3 background_light_sample(KernelGlobals kg, float3 P, float2 rand, ccl_private float *pdf)
ccl_device_forceinline bool background_light_tree_parameters(const float3 centroid, const float t, ccl_private float &cos_theta_u, ccl_private float2 &distance, ccl_private float3 &point_to_centroid, ccl_private float &theta_d)
ccl_device_inline bool background_portal_data_fetch_and_check_side(KernelGlobals kg, float3 P, int index, ccl_private float3 *lightpos, ccl_private float3 *dir)
ccl_device float3 background_portal_sample(KernelGlobals kg, float3 P, float2 rand, int num_possible, ccl_private int *sampled_portal, ccl_private float *pdf)
ccl_device int background_num_possible_portals(KernelGlobals kg, float3 P)
CCL_NAMESPACE_BEGIN ccl_device float3 background_map_sample(KernelGlobals kg, float2 rand, ccl_private float *pdf)
ccl_device_inline float background_portal_pdf(KernelGlobals kg, float3 P, float3 direction, int ignore_portal, ccl_private bool *is_possible)
ccl_device float background_light_pdf(KernelGlobals kg, float3 P, float3 direction)
ccl_device_inline float background_sun_pdf(KernelGlobals kg, float3 D)
ccl_device float background_map_pdf(KernelGlobals kg, float3 direction)
ccl_device_inline float3 background_sun_sample(KernelGlobals kg, float2 rand, ccl_private float *pdf)
ccl_device_inline float3 ellipse_sample(float3 ru, float3 rv, float2 rand)
ccl_device float light_pdf_area_to_solid_angle(const float3 Ng, const float3 I, float t)
CCL_NAMESPACE_BEGIN ccl_device_inline float2 zero_float2()
Definition math_float2.h:14
ccl_device_inline float2 normalize_len(const float2 a, ccl_private float *t)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:15
ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_tmin, float ray_tmax, float3 quad_P, float3 inv_quad_u, float3 inv_quad_v, float3 quad_n, ccl_private float3 *isect_P, ccl_private float *isect_t, ccl_private float *isect_u, ccl_private float *isect_v, bool ellipse)
#define N
#define M_PI_F
Definition mikk_util.hh:15
ccl_device float3 sample_uniform_sphere(const float2 rand)
ccl_device_inline float pdf_uniform_cone(const float3 N, float3 D, float angle)
ccl_device_inline float3 sample_uniform_cone(const float3 N, const float one_minus_cos_angle, const float2 rand, ccl_private float *cos_theta, ccl_private float *pdf)
#define M_2PI_F
Definition sky_float3.h:23
#define FLT_MAX
Definition stdcycles.h:14
float x
float y
float max
ccl_device_inline float inverse_lerp(float a, float b, float x)
Definition util/math.h:550
ccl_device_inline int float_to_int(float f)
Definition util/math.h:424
ccl_device_inline float3 float4_to_float3(const float4 a)
Definition util/math.h:535
ccl_device_inline float one_minus_cos(const float angle)
Definition util/math.h:803
ccl_device_inline int clamp(int a, int mn, int mx)
Definition util/math.h:379