Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/light/background.h
| /* SPDX-License-Identifier: Apache-2.0 | /* SPDX-License-Identifier: Apache-2.0 | ||||
| * Copyright 2011-2022 Blender Foundation */ | * Copyright 2011-2022 Blender Foundation */ | ||||
| #pragma once | #pragma once | ||||
| #include "kernel/light/area.h" | |||||
| #include "kernel/light/common.h" | #include "kernel/light/common.h" | ||||
| CCL_NAMESPACE_BEGIN | CCL_NAMESPACE_BEGIN | ||||
| /* Background Light */ | /* Background Light */ | ||||
| ccl_device float3 background_map_sample(KernelGlobals kg, | ccl_device float3 background_map_sample(KernelGlobals kg, | ||||
| float randu, | float randu, | ||||
| ▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | ccl_device float background_map_pdf(KernelGlobals kg, float3 direction) | ||||
| float2 cdf_v = kernel_data_fetch(light_background_marginal_cdf, index_v); | float2 cdf_v = kernel_data_fetch(light_background_marginal_cdf, index_v); | ||||
| return (cdf_u.x * cdf_v.x) / denom; | return (cdf_u.x * cdf_v.x) / denom; | ||||
| } | } | ||||
| ccl_device_inline bool background_portal_data_fetch_and_check_side( | 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) | KernelGlobals kg, float3 P, int index, ccl_private float3 *lightpos, ccl_private float3 *dir) | ||||
| { | { | ||||
| int portal = kernel_data.background.portal_offset + index; | int portal = kernel_data.integrator.portal_offset + index; | ||||
| const ccl_global KernelLight *klight = &kernel_data_fetch(lights, portal); | const ccl_global KernelLight *klight = &kernel_data_fetch(lights, portal); | ||||
| *lightpos = make_float3(klight->co[0], klight->co[1], klight->co[2]); | *lightpos = klight->co; | ||||
| *dir = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); | *dir = klight->area.dir; | ||||
| /* Check whether portal is on the right side. */ | /* Check whether portal is on the right side. */ | ||||
| if (dot(*dir, P - *lightpos) > 1e-4f) | if (dot(*dir, P - *lightpos) > 1e-4f) | ||||
| return true; | return true; | ||||
| return false; | return false; | ||||
| } | } | ||||
| ccl_device_inline float background_portal_pdf( | ccl_device_inline float background_portal_pdf( | ||||
| KernelGlobals kg, float3 P, float3 direction, int ignore_portal, ccl_private bool *is_possible) | KernelGlobals kg, float3 P, float3 direction, int ignore_portal, ccl_private bool *is_possible) | ||||
| { | { | ||||
| float portal_pdf = 0.0f; | float portal_pdf = 0.0f; | ||||
| int num_possible = 0; | int num_possible = 0; | ||||
| for (int p = 0; p < kernel_data.background.num_portals; p++) { | for (int p = 0; p < kernel_data.integrator.num_portals; p++) { | ||||
| if (p == ignore_portal) | if (p == ignore_portal) | ||||
| continue; | continue; | ||||
| float3 lightpos, dir; | float3 lightpos, dir; | ||||
| if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir)) | if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir)) | ||||
| continue; | continue; | ||||
| /* There's a portal that could be sampled from this position. */ | /* There's a portal that could be sampled from this position. */ | ||||
| if (is_possible) { | if (is_possible) { | ||||
| *is_possible = true; | *is_possible = true; | ||||
| } | } | ||||
| num_possible++; | num_possible++; | ||||
| int portal = kernel_data.background.portal_offset + p; | int portal = kernel_data.integrator.portal_offset + p; | ||||
| const ccl_global KernelLight *klight = &kernel_data_fetch(lights, portal); | const ccl_global KernelLight *klight = &kernel_data_fetch(lights, portal); | ||||
| float3 axisu = make_float3( | float3 extentu = klight->area.extentu; | ||||
| klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); | float3 extentv = klight->area.extentv; | ||||
| float3 axisv = make_float3( | |||||
| klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); | |||||
| bool is_round = (klight->area.invarea < 0.0f); | bool is_round = (klight->area.invarea < 0.0f); | ||||
| if (!ray_quad_intersect(P, | if (!ray_quad_intersect(P, | ||||
| direction, | direction, | ||||
| 1e-4f, | 1e-4f, | ||||
| FLT_MAX, | FLT_MAX, | ||||
| lightpos, | lightpos, | ||||
| axisu, | extentu, | ||||
| axisv, | extentv, | ||||
| dir, | dir, | ||||
| NULL, | NULL, | ||||
| NULL, | NULL, | ||||
| NULL, | NULL, | ||||
| NULL, | NULL, | ||||
| is_round)) | is_round)) | ||||
| continue; | continue; | ||||
| if (is_round) { | if (is_round) { | ||||
| float t; | float t; | ||||
| float3 D = normalize_len(lightpos - P, &t); | float3 D = normalize_len(lightpos - P, &t); | ||||
| portal_pdf += fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t); | portal_pdf += fabsf(klight->area.invarea) * lamp_light_pdf(dir, -D, t); | ||||
| } | } | ||||
| else { | else { | ||||
| portal_pdf += rect_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false); | portal_pdf += area_light_rect_sample(P, &lightpos, extentu, extentv, 0.0f, 0.0f, false); | ||||
| } | } | ||||
| } | } | ||||
| if (ignore_portal >= 0) { | if (ignore_portal >= 0) { | ||||
| /* We have skipped a portal that could be sampled as well. */ | /* We have skipped a portal that could be sampled as well. */ | ||||
| num_possible++; | num_possible++; | ||||
| } | } | ||||
| return (num_possible > 0) ? portal_pdf / num_possible : 0.0f; | return (num_possible > 0) ? portal_pdf / num_possible : 0.0f; | ||||
| } | } | ||||
| ccl_device int background_num_possible_portals(KernelGlobals kg, float3 P) | ccl_device int background_num_possible_portals(KernelGlobals kg, float3 P) | ||||
| { | { | ||||
| int num_possible_portals = 0; | int num_possible_portals = 0; | ||||
| for (int p = 0; p < kernel_data.background.num_portals; p++) { | for (int p = 0; p < kernel_data.integrator.num_portals; p++) { | ||||
| float3 lightpos, dir; | float3 lightpos, dir; | ||||
| if (background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir)) | if (background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir)) | ||||
| num_possible_portals++; | num_possible_portals++; | ||||
| } | } | ||||
| return num_possible_portals; | return num_possible_portals; | ||||
| } | } | ||||
| ccl_device float3 background_portal_sample(KernelGlobals kg, | ccl_device float3 background_portal_sample(KernelGlobals kg, | ||||
| float3 P, | float3 P, | ||||
| float randu, | float randu, | ||||
| float randv, | float randv, | ||||
| int num_possible, | int num_possible, | ||||
| ccl_private int *sampled_portal, | ccl_private int *sampled_portal, | ||||
| ccl_private float *pdf) | ccl_private float *pdf) | ||||
| { | { | ||||
| /* Pick a portal, then re-normalize randv. */ | /* Pick a portal, then re-normalize randv. */ | ||||
| randv *= num_possible; | randv *= num_possible; | ||||
| int portal = (int)randv; | int portal = (int)randv; | ||||
| randv -= portal; | randv -= portal; | ||||
| /* TODO(sergey): Some smarter way of finding portal to sample | /* TODO(sergey): Some smarter way of finding portal to sample | ||||
| * is welcome. | * is welcome. | ||||
| */ | */ | ||||
| for (int p = 0; p < kernel_data.background.num_portals; p++) { | for (int p = 0; p < kernel_data.integrator.num_portals; p++) { | ||||
| /* Search for the sampled portal. */ | /* Search for the sampled portal. */ | ||||
| float3 lightpos, dir; | float3 lightpos, dir; | ||||
| if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir)) | if (!background_portal_data_fetch_and_check_side(kg, P, p, &lightpos, &dir)) | ||||
| continue; | continue; | ||||
| if (portal == 0) { | if (portal == 0) { | ||||
| /* p is the portal to be sampled. */ | /* p is the portal to be sampled. */ | ||||
| int portal = kernel_data.background.portal_offset + p; | int portal = kernel_data.integrator.portal_offset + p; | ||||
| const ccl_global KernelLight *klight = &kernel_data_fetch(lights, portal); | const ccl_global KernelLight *klight = &kernel_data_fetch(lights, portal); | ||||
| float3 axisu = make_float3( | float3 extentu = klight->area.extentu; | ||||
| klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); | float3 extentv = klight->area.extentv; | ||||
| float3 axisv = make_float3( | |||||
| klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); | |||||
| bool is_round = (klight->area.invarea < 0.0f); | bool is_round = (klight->area.invarea < 0.0f); | ||||
| float3 D; | float3 D; | ||||
| if (is_round) { | if (is_round) { | ||||
| lightpos += ellipse_sample(axisu * 0.5f, axisv * 0.5f, randu, randv); | lightpos += ellipse_sample(extentu * 0.5f, extentv * 0.5f, randu, randv); | ||||
| float t; | float t; | ||||
| D = normalize_len(lightpos - P, &t); | D = normalize_len(lightpos - P, &t); | ||||
| *pdf = fabsf(klight->area.invarea) * lamp_light_pdf(kg, dir, -D, t); | *pdf = fabsf(klight->area.invarea) * lamp_light_pdf(dir, -D, t); | ||||
| } | } | ||||
| else { | else { | ||||
| *pdf = rect_light_sample(P, &lightpos, axisu, axisv, randu, randv, true); | *pdf = area_light_rect_sample(P, &lightpos, extentu, extentv, randu, randv, true); | ||||
| D = normalize(lightpos - P); | D = normalize(lightpos - P); | ||||
| } | } | ||||
| *pdf /= num_possible; | *pdf /= num_possible; | ||||
| *sampled_portal = p; | *sampled_portal = p; | ||||
| return D; | return D; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 142 Lines • ▼ Show 20 Lines | if (!is_possible) { | ||||
| * fallback. */ | * fallback. */ | ||||
| portal_method_pdf = 0.0f; | portal_method_pdf = 0.0f; | ||||
| } | } | ||||
| } | } | ||||
| float pdf_fac = (portal_method_pdf + sun_method_pdf + map_method_pdf); | float pdf_fac = (portal_method_pdf + sun_method_pdf + map_method_pdf); | ||||
| if (pdf_fac == 0.0f) { | if (pdf_fac == 0.0f) { | ||||
| /* Use uniform as a fallback if we can't use any strategy. */ | /* Use uniform as a fallback if we can't use any strategy. */ | ||||
| return kernel_data.integrator.pdf_lights / M_4PI_F; | return 1.0f / M_4PI_F; | ||||
| } | } | ||||
| pdf_fac = 1.0f / pdf_fac; | pdf_fac = 1.0f / pdf_fac; | ||||
| portal_method_pdf *= pdf_fac; | portal_method_pdf *= pdf_fac; | ||||
| sun_method_pdf *= pdf_fac; | sun_method_pdf *= pdf_fac; | ||||
| map_method_pdf *= pdf_fac; | map_method_pdf *= pdf_fac; | ||||
| float pdf = portal_pdf * portal_method_pdf; | float pdf = portal_pdf * portal_method_pdf; | ||||
| if (sun_method_pdf != 0.0f) { | if (sun_method_pdf != 0.0f) { | ||||
| pdf += background_sun_pdf(kg, direction) * sun_method_pdf; | pdf += background_sun_pdf(kg, direction) * sun_method_pdf; | ||||
| } | } | ||||
| if (map_method_pdf != 0.0f) { | if (map_method_pdf != 0.0f) { | ||||
| pdf += background_map_pdf(kg, direction) * map_method_pdf; | pdf += background_map_pdf(kg, direction) * map_method_pdf; | ||||
| } | } | ||||
| return pdf * kernel_data.integrator.pdf_lights; | return pdf; | ||||
| } | } | ||||
| CCL_NAMESPACE_END | CCL_NAMESPACE_END | ||||