diff options
Diffstat (limited to 'intern/cycles/kernel/kernel_light.h')
-rw-r--r-- | intern/cycles/kernel/kernel_light.h | 875 |
1 files changed, 0 insertions, 875 deletions
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h deleted file mode 100644 index b3eaed4fcb0..00000000000 --- a/intern/cycles/kernel/kernel_light.h +++ /dev/null @@ -1,875 +0,0 @@ -/* - * Copyright 2011-2013 Blender Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "geom/geom.h" - -#include "kernel_light_background.h" -#include "kernel_montecarlo.h" -#include "kernel_projection.h" -#include "kernel_types.h" - -CCL_NAMESPACE_BEGIN - -/* Light Sample result */ - -typedef struct LightSample { - float3 P; /* position on light, or direction for distant light */ - float3 Ng; /* normal on light */ - float3 D; /* direction from shading point to light */ - float t; /* distance to light (FLT_MAX for distant light) */ - float u, v; /* parametric coordinate on primitive */ - float pdf; /* light sampling probability density function */ - float eval_fac; /* intensity multiplier */ - int object; /* object id for triangle/curve lights */ - int prim; /* primitive id for triangle/curve lights */ - int shader; /* shader id */ - int lamp; /* lamp id */ - LightType type; /* type of light */ -} LightSample; - -/* Regular Light */ - -template<bool in_volume_segment> -ccl_device_inline bool light_sample(KernelGlobals kg, - const int lamp, - const float randu, - const float randv, - const float3 P, - const uint32_t path_flag, - ccl_private LightSample *ls) -{ - const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp); - if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) { - if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) { - return false; - } - } - - LightType type = (LightType)klight->type; - ls->type = type; - ls->shader = klight->shader_id; - ls->object = PRIM_NONE; - ls->prim = PRIM_NONE; - ls->lamp = lamp; - ls->u = randu; - ls->v = randv; - - if (in_volume_segment && (type == LIGHT_DISTANT || type == LIGHT_BACKGROUND)) { - /* Distant lights in a volume get a dummy sample, position will not actually - * be used in that case. Only when sampling from a specific scatter position - * do we actually need to evaluate these. */ - ls->P = zero_float3(); - ls->Ng = zero_float3(); - ls->D = zero_float3(); - ls->pdf = true; - ls->t = FLT_MAX; - return true; - } - - if (type == LIGHT_DISTANT) { - /* distant light */ - float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]); - float3 D = lightD; - float radius = klight->distant.radius; - float invarea = klight->distant.invarea; - - if (radius > 0.0f) - D = distant_light_sample(D, radius, randu, randv); - - ls->P = D; - ls->Ng = D; - ls->D = -D; - ls->t = FLT_MAX; - - float costheta = dot(lightD, D); - ls->pdf = invarea / (costheta * costheta * costheta); - ls->eval_fac = ls->pdf; - } -#ifdef __BACKGROUND_MIS__ - else if (type == LIGHT_BACKGROUND) { - /* infinite area light (e.g. light dome or env light) */ - float3 D = -background_light_sample(kg, P, randu, randv, &ls->pdf); - - ls->P = D; - ls->Ng = D; - ls->D = -D; - ls->t = FLT_MAX; - ls->eval_fac = 1.0f; - } -#endif - else { - ls->P = make_float3(klight->co[0], klight->co[1], klight->co[2]); - - if (type == LIGHT_POINT || type == LIGHT_SPOT) { - float radius = klight->spot.radius; - - if (radius > 0.0f) - /* sphere light */ - ls->P += sphere_light_sample(P, ls->P, radius, randu, randv); - - ls->D = normalize_len(ls->P - P, &ls->t); - ls->Ng = -ls->D; - - float invarea = klight->spot.invarea; - ls->eval_fac = (0.25f * M_1_PI_F) * invarea; - ls->pdf = invarea; - - if (type == LIGHT_SPOT) { - /* spot light attenuation */ - float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]); - ls->eval_fac *= spot_light_attenuation( - dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng); - if (ls->eval_fac == 0.0f) { - return false; - } - } - float2 uv = map_to_sphere(ls->Ng); - ls->u = uv.x; - ls->v = uv.y; - - ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t); - } - else { - /* area light */ - float3 axisu = make_float3( - klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); - float3 axisv = make_float3( - klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); - float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); - float invarea = fabsf(klight->area.invarea); - bool is_round = (klight->area.invarea < 0.0f); - - if (!in_volume_segment) { - if (dot(ls->P - P, Ng) > 0.0f) { - return false; - } - } - - float3 inplane; - - if (is_round || in_volume_segment) { - inplane = ellipse_sample(axisu * 0.5f, axisv * 0.5f, randu, randv); - ls->P += inplane; - ls->pdf = invarea; - } - else { - inplane = ls->P; - - float3 sample_axisu = axisu; - float3 sample_axisv = axisv; - - if (klight->area.tan_spread > 0.0f) { - if (!light_spread_clamp_area_light( - P, Ng, &ls->P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) { - return false; - } - } - - ls->pdf = rect_light_sample(P, &ls->P, sample_axisu, sample_axisv, randu, randv, true); - inplane = ls->P - inplane; - } - - ls->u = dot(inplane, axisu) * (1.0f / dot(axisu, axisu)) + 0.5f; - ls->v = dot(inplane, axisv) * (1.0f / dot(axisv, axisv)) + 0.5f; - - ls->Ng = Ng; - ls->D = normalize_len(ls->P - P, &ls->t); - - ls->eval_fac = 0.25f * invarea; - - if (klight->area.tan_spread > 0.0f) { - /* Area Light spread angle attenuation */ - ls->eval_fac *= light_spread_attenuation( - ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread); - } - - if (is_round) { - ls->pdf *= lamp_light_pdf(kg, Ng, -ls->D, ls->t); - } - } - } - - ls->pdf *= kernel_data.integrator.pdf_lights; - - return (ls->pdf > 0.0f); -} - -ccl_device bool lights_intersect(KernelGlobals kg, - ccl_private const Ray *ccl_restrict ray, - ccl_private Intersection *ccl_restrict isect, - const int last_prim, - const int last_object, - const int last_type, - const uint32_t path_flag) -{ - for (int lamp = 0; lamp < kernel_data.integrator.num_all_lights; lamp++) { - const ccl_global KernelLight *klight = &kernel_tex_fetch(__lights, lamp); - - if (path_flag & PATH_RAY_CAMERA) { - if (klight->shader_id & SHADER_EXCLUDE_CAMERA) { - continue; - } - } - else { - if (!(klight->shader_id & SHADER_USE_MIS)) { - continue; - } - } - - if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) { - if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) { - continue; - } - } - - LightType type = (LightType)klight->type; - float t = 0.0f, u = 0.0f, v = 0.0f; - - if (type == LIGHT_POINT || type == LIGHT_SPOT) { - /* Sphere light. */ - const float3 lightP = make_float3(klight->co[0], klight->co[1], klight->co[2]); - const float radius = klight->spot.radius; - if (radius == 0.0f) { - continue; - } - - float3 P; - if (!ray_aligned_disk_intersect(ray->P, ray->D, ray->t, lightP, radius, &P, &t)) { - continue; - } - } - else if (type == LIGHT_AREA) { - /* Area light. */ - const float invarea = fabsf(klight->area.invarea); - const bool is_round = (klight->area.invarea < 0.0f); - if (invarea == 0.0f) { - continue; - } - - const float3 axisu = make_float3( - klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); - const float3 axisv = make_float3( - klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); - const float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); - - /* One sided. */ - if (dot(ray->D, Ng) >= 0.0f) { - continue; - } - - const float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]); - - float3 P; - if (!ray_quad_intersect( - ray->P, ray->D, 0.0f, ray->t, light_P, axisu, axisv, Ng, &P, &t, &u, &v, is_round)) { - continue; - } - } - else { - continue; - } - - if (t < isect->t && - !(last_prim == lamp && last_object == OBJECT_NONE && last_type == PRIMITIVE_LAMP)) { - isect->t = t; - isect->u = u; - isect->v = v; - isect->type = PRIMITIVE_LAMP; - isect->prim = lamp; - isect->object = OBJECT_NONE; - } - } - - return isect->prim != PRIM_NONE; -} - -ccl_device bool light_sample_from_distant_ray(KernelGlobals kg, - const float3 ray_D, - const int lamp, - ccl_private LightSample *ccl_restrict ls) -{ - ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp); - const int shader = klight->shader_id; - const float radius = klight->distant.radius; - const LightType type = (LightType)klight->type; - - if (type != LIGHT_DISTANT) { - return false; - } - if (!(shader & SHADER_USE_MIS)) { - return false; - } - if (radius == 0.0f) { - return false; - } - - /* a distant light is infinitely far away, but equivalent to a disk - * shaped light exactly 1 unit away from the current shading point. - * - * radius t^2/cos(theta) - * <----------> t = sqrt(1^2 + tan(theta)^2) - * tan(th) area = radius*radius*pi - * <-----> - * \ | (1 + tan(theta)^2)/cos(theta) - * \ | (1 + tan(acos(cos(theta)))^2)/cos(theta) - * t \th| 1 simplifies to - * \-| 1/(cos(theta)^3) - * \| magic! - * P - */ - - float3 lightD = make_float3(klight->co[0], klight->co[1], klight->co[2]); - float costheta = dot(-lightD, ray_D); - float cosangle = klight->distant.cosangle; - - if (costheta < cosangle) - return false; - - ls->type = type; - ls->shader = klight->shader_id; - ls->object = PRIM_NONE; - ls->prim = PRIM_NONE; - ls->lamp = lamp; - /* todo: missing texture coordinates */ - ls->u = 0.0f; - ls->v = 0.0f; - ls->t = FLT_MAX; - ls->P = -ray_D; - ls->Ng = -ray_D; - ls->D = ray_D; - - /* compute pdf */ - float invarea = klight->distant.invarea; - ls->pdf = invarea / (costheta * costheta * costheta); - ls->pdf *= kernel_data.integrator.pdf_lights; - ls->eval_fac = ls->pdf; - - return true; -} - -ccl_device bool light_sample_from_intersection(KernelGlobals kg, - ccl_private const Intersection *ccl_restrict isect, - const float3 ray_P, - const float3 ray_D, - ccl_private LightSample *ccl_restrict ls) -{ - const int lamp = isect->prim; - ccl_global const KernelLight *klight = &kernel_tex_fetch(__lights, lamp); - LightType type = (LightType)klight->type; - ls->type = type; - ls->shader = klight->shader_id; - ls->object = PRIM_NONE; - ls->prim = PRIM_NONE; - ls->lamp = lamp; - /* todo: missing texture coordinates */ - ls->t = isect->t; - ls->P = ray_P + ray_D * ls->t; - ls->D = ray_D; - - if (type == LIGHT_POINT || type == LIGHT_SPOT) { - ls->Ng = -ray_D; - - float invarea = klight->spot.invarea; - ls->eval_fac = (0.25f * M_1_PI_F) * invarea; - ls->pdf = invarea; - - if (type == LIGHT_SPOT) { - /* spot light attenuation */ - float3 dir = make_float3(klight->spot.dir[0], klight->spot.dir[1], klight->spot.dir[2]); - ls->eval_fac *= spot_light_attenuation( - dir, klight->spot.spot_angle, klight->spot.spot_smooth, ls->Ng); - - if (ls->eval_fac == 0.0f) { - return false; - } - } - float2 uv = map_to_sphere(ls->Ng); - ls->u = uv.x; - ls->v = uv.y; - - /* compute pdf */ - if (ls->t != FLT_MAX) - ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t); - } - else if (type == LIGHT_AREA) { - /* area light */ - float invarea = fabsf(klight->area.invarea); - - float3 axisu = make_float3( - klight->area.axisu[0], klight->area.axisu[1], klight->area.axisu[2]); - float3 axisv = make_float3( - klight->area.axisv[0], klight->area.axisv[1], klight->area.axisv[2]); - float3 Ng = make_float3(klight->area.dir[0], klight->area.dir[1], klight->area.dir[2]); - float3 light_P = make_float3(klight->co[0], klight->co[1], klight->co[2]); - - ls->u = isect->u; - ls->v = isect->v; - ls->D = ray_D; - ls->Ng = Ng; - - const bool is_round = (klight->area.invarea < 0.0f); - if (is_round) { - ls->pdf = invarea * lamp_light_pdf(kg, Ng, -ray_D, ls->t); - } - else { - float3 sample_axisu = axisu; - float3 sample_axisv = axisv; - - if (klight->area.tan_spread > 0.0f) { - if (!light_spread_clamp_area_light( - ray_P, Ng, &light_P, &sample_axisu, &sample_axisv, klight->area.tan_spread)) { - return false; - } - } - - ls->pdf = rect_light_sample(ray_P, &light_P, sample_axisu, sample_axisv, 0, 0, false); - } - ls->eval_fac = 0.25f * invarea; - - if (klight->area.tan_spread > 0.0f) { - /* Area Light spread angle attenuation */ - ls->eval_fac *= light_spread_attenuation( - ls->D, ls->Ng, klight->area.tan_spread, klight->area.normalize_spread); - if (ls->eval_fac == 0.0f) { - return false; - } - } - } - else { - kernel_assert(!"Invalid lamp type in light_sample_from_intersection"); - return false; - } - - ls->pdf *= kernel_data.integrator.pdf_lights; - - return true; -} - -/* Triangle Light */ - -/* returns true if the triangle is has motion blur or an instancing transform applied */ -ccl_device_inline bool triangle_world_space_vertices( - KernelGlobals kg, int object, int prim, float time, float3 V[3]) -{ - bool has_motion = false; - const int object_flag = kernel_tex_fetch(__object_flag, object); - - if (object_flag & SD_OBJECT_HAS_VERTEX_MOTION && time >= 0.0f) { - motion_triangle_vertices(kg, object, prim, time, V); - has_motion = true; - } - else { - triangle_vertices(kg, prim, V); - } - - if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { -#ifdef __OBJECT_MOTION__ - float object_time = (time >= 0.0f) ? time : 0.5f; - Transform tfm = object_fetch_transform_motion_test(kg, object, object_time, NULL); -#else - Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM); -#endif - V[0] = transform_point(&tfm, V[0]); - V[1] = transform_point(&tfm, V[1]); - V[2] = transform_point(&tfm, V[2]); - has_motion = true; - } - return has_motion; -} - -ccl_device_inline float triangle_light_pdf_area(KernelGlobals kg, - const float3 Ng, - const float3 I, - float t) -{ - float pdf = kernel_data.integrator.pdf_triangles; - float cos_pi = fabsf(dot(Ng, I)); - - if (cos_pi == 0.0f) - return 0.0f; - - return t * t * pdf / cos_pi; -} - -ccl_device_forceinline float triangle_light_pdf(KernelGlobals kg, - ccl_private const ShaderData *sd, - float t) -{ - /* A naive heuristic to decide between costly solid angle sampling - * and simple area sampling, comparing the distance to the triangle plane - * to the length of the edges of the triangle. */ - - float3 V[3]; - bool has_motion = triangle_world_space_vertices(kg, sd->object, sd->prim, sd->time, V); - - const float3 e0 = V[1] - V[0]; - const float3 e1 = V[2] - V[0]; - const float3 e2 = V[2] - V[1]; - const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2))); - const float3 N = cross(e0, e1); - const float distance_to_plane = fabsf(dot(N, sd->I * t)) / dot(N, N); - - if (longest_edge_squared > distance_to_plane * distance_to_plane) { - /* sd contains the point on the light source - * calculate Px, the point that we're shading */ - const float3 Px = sd->P + sd->I * t; - const float3 v0_p = V[0] - Px; - const float3 v1_p = V[1] - Px; - const float3 v2_p = V[2] - Px; - - const float3 u01 = safe_normalize(cross(v0_p, v1_p)); - const float3 u02 = safe_normalize(cross(v0_p, v2_p)); - const float3 u12 = safe_normalize(cross(v1_p, v2_p)); - - const float alpha = fast_acosf(dot(u02, u01)); - const float beta = fast_acosf(-dot(u01, u12)); - const float gamma = fast_acosf(dot(u02, u12)); - const float solid_angle = alpha + beta + gamma - M_PI_F; - - /* pdf_triangles is calculated over triangle area, but we're not sampling over its area */ - if (UNLIKELY(solid_angle == 0.0f)) { - return 0.0f; - } - else { - float area = 1.0f; - if (has_motion) { - /* get the center frame vertices, this is what the PDF was calculated from */ - triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V); - area = triangle_area(V[0], V[1], V[2]); - } - else { - area = 0.5f * len(N); - } - const float pdf = area * kernel_data.integrator.pdf_triangles; - return pdf / solid_angle; - } - } - else { - float pdf = triangle_light_pdf_area(kg, sd->Ng, sd->I, t); - if (has_motion) { - const float area = 0.5f * len(N); - if (UNLIKELY(area == 0.0f)) { - return 0.0f; - } - /* scale the PDF. - * area = the area the sample was taken from - * area_pre = the are from which pdf_triangles was calculated from */ - triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V); - const float area_pre = triangle_area(V[0], V[1], V[2]); - pdf = pdf * area_pre / area; - } - return pdf; - } -} - -template<bool in_volume_segment> -ccl_device_forceinline void triangle_light_sample(KernelGlobals kg, - int prim, - int object, - float randu, - float randv, - float time, - ccl_private LightSample *ls, - const float3 P) -{ - /* A naive heuristic to decide between costly solid angle sampling - * and simple area sampling, comparing the distance to the triangle plane - * to the length of the edges of the triangle. */ - - float3 V[3]; - bool has_motion = triangle_world_space_vertices(kg, object, prim, time, V); - - const float3 e0 = V[1] - V[0]; - const float3 e1 = V[2] - V[0]; - const float3 e2 = V[2] - V[1]; - const float longest_edge_squared = max(len_squared(e0), max(len_squared(e1), len_squared(e2))); - const float3 N0 = cross(e0, e1); - float Nl = 0.0f; - ls->Ng = safe_normalize_len(N0, &Nl); - float area = 0.5f * Nl; - - /* flip normal if necessary */ - const int object_flag = kernel_tex_fetch(__object_flag, object); - if (object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) { - ls->Ng = -ls->Ng; - } - ls->eval_fac = 1.0f; - ls->shader = kernel_tex_fetch(__tri_shader, prim); - ls->object = object; - ls->prim = prim; - ls->lamp = LAMP_NONE; - ls->shader |= SHADER_USE_MIS; - ls->type = LIGHT_TRIANGLE; - - float distance_to_plane = fabsf(dot(N0, V[0] - P) / dot(N0, N0)); - - if (!in_volume_segment && (longest_edge_squared > distance_to_plane * distance_to_plane)) { - /* see James Arvo, "Stratified Sampling of Spherical Triangles" - * http://www.graphics.cornell.edu/pubs/1995/Arv95c.pdf */ - - /* project the triangle to the unit sphere - * and calculate its edges and angles */ - const float3 v0_p = V[0] - P; - const float3 v1_p = V[1] - P; - const float3 v2_p = V[2] - P; - - const float3 u01 = safe_normalize(cross(v0_p, v1_p)); - const float3 u02 = safe_normalize(cross(v0_p, v2_p)); - const float3 u12 = safe_normalize(cross(v1_p, v2_p)); - - const float3 A = safe_normalize(v0_p); - const float3 B = safe_normalize(v1_p); - const float3 C = safe_normalize(v2_p); - - const float cos_alpha = dot(u02, u01); - const float cos_beta = -dot(u01, u12); - const float cos_gamma = dot(u02, u12); - - /* calculate dihedral angles */ - const float alpha = fast_acosf(cos_alpha); - const float beta = fast_acosf(cos_beta); - const float gamma = fast_acosf(cos_gamma); - /* the area of the unit spherical triangle = solid angle */ - const float solid_angle = alpha + beta + gamma - M_PI_F; - - /* precompute a few things - * these could be re-used to take several samples - * as they are independent of randu/randv */ - const float cos_c = dot(A, B); - const float sin_alpha = fast_sinf(alpha); - const float product = sin_alpha * cos_c; - - /* Select a random sub-area of the spherical triangle - * and calculate the third vertex C_ of that new triangle */ - const float phi = randu * solid_angle - alpha; - float s, t; - fast_sincosf(phi, &s, &t); - const float u = t - cos_alpha; - const float v = s + product; - - const float3 U = safe_normalize(C - dot(C, A) * A); - - float q = 1.0f; - const float det = ((v * s + u * t) * sin_alpha); - if (det != 0.0f) { - q = ((v * t - u * s) * cos_alpha - v) / det; - } - const float temp = max(1.0f - q * q, 0.0f); - - const float3 C_ = safe_normalize(q * A + sqrtf(temp) * U); - - /* Finally, select a random point along the edge of the new triangle - * That point on the spherical triangle is the sampled ray direction */ - const float z = 1.0f - randv * (1.0f - dot(C_, B)); - ls->D = z * B + safe_sqrtf(1.0f - z * z) * safe_normalize(C_ - dot(C_, B) * B); - - /* calculate intersection with the planar triangle */ - if (!ray_triangle_intersect(P, - ls->D, - FLT_MAX, -#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - (ssef *)V, -#else - V[0], - V[1], - V[2], -#endif - &ls->u, - &ls->v, - &ls->t)) { - ls->pdf = 0.0f; - return; - } - - ls->P = P + ls->D * ls->t; - - /* pdf_triangles is calculated over triangle area, but we're sampling over solid angle */ - if (UNLIKELY(solid_angle == 0.0f)) { - ls->pdf = 0.0f; - return; - } - else { - if (has_motion) { - /* get the center frame vertices, this is what the PDF was calculated from */ - triangle_world_space_vertices(kg, object, prim, -1.0f, V); - area = triangle_area(V[0], V[1], V[2]); - } - const float pdf = area * kernel_data.integrator.pdf_triangles; - ls->pdf = pdf / solid_angle; - } - } - else { - /* compute random point in triangle. From Eric Heitz's "A Low-Distortion Map Between Triangle - * and Square" */ - float u = randu; - float v = randv; - if (v > u) { - u *= 0.5f; - v -= u; - } - else { - v *= 0.5f; - u -= v; - } - - const float t = 1.0f - u - v; - ls->P = u * V[0] + v * V[1] + t * V[2]; - /* compute incoming direction, distance and pdf */ - ls->D = normalize_len(ls->P - P, &ls->t); - ls->pdf = triangle_light_pdf_area(kg, ls->Ng, -ls->D, ls->t); - if (has_motion && area != 0.0f) { - /* scale the PDF. - * area = the area the sample was taken from - * area_pre = the are from which pdf_triangles was calculated from */ - triangle_world_space_vertices(kg, object, prim, -1.0f, V); - const float area_pre = triangle_area(V[0], V[1], V[2]); - ls->pdf = ls->pdf * area_pre / area; - } - ls->u = u; - ls->v = v; - } -} - -/* Light Distribution */ - -ccl_device int light_distribution_sample(KernelGlobals kg, ccl_private float *randu) -{ - /* This is basically std::upper_bound as used by PBRT, to find a point light or - * triangle to emit from, proportional to area. a good improvement would be to - * also sample proportional to power, though it's not so well defined with - * arbitrary shaders. */ - int first = 0; - int len = kernel_data.integrator.num_distribution + 1; - float r = *randu; - - do { - int half_len = len >> 1; - int middle = first + half_len; - - if (r < kernel_tex_fetch(__light_distribution, middle).totarea) { - len = half_len; - } - else { - first = middle + 1; - len = len - half_len - 1; - } - } while (len > 0); - - /* Clamping should not be needed but float rounding errors seem to - * make this fail on rare occasions. */ - int index = clamp(first - 1, 0, kernel_data.integrator.num_distribution - 1); - - /* Rescale to reuse random number. this helps the 2D samples within - * each area light be stratified as well. */ - float distr_min = kernel_tex_fetch(__light_distribution, index).totarea; - float distr_max = kernel_tex_fetch(__light_distribution, index + 1).totarea; - *randu = (r - distr_min) / (distr_max - distr_min); - - return index; -} - -/* Generic Light */ - -ccl_device_inline bool light_select_reached_max_bounces(KernelGlobals kg, int index, int bounce) -{ - return (bounce > kernel_tex_fetch(__lights, index).max_bounces); -} - -template<bool in_volume_segment> -ccl_device_noinline bool light_distribution_sample(KernelGlobals kg, - float randu, - const float randv, - const float time, - const float3 P, - const int bounce, - const uint32_t path_flag, - ccl_private LightSample *ls) -{ - /* Sample light index from distribution. */ - const int index = light_distribution_sample(kg, &randu); - ccl_global const KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, - index); - const int prim = kdistribution->prim; - - if (prim >= 0) { - /* Mesh light. */ - const int object = kdistribution->mesh_light.object_id; - - /* Exclude synthetic meshes from shadow catcher pass. */ - if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) && - !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_SHADOW_CATCHER)) { - return false; - } - - const int shader_flag = kdistribution->mesh_light.shader_flag; - triangle_light_sample<in_volume_segment>(kg, prim, object, randu, randv, time, ls, P); - ls->shader |= shader_flag; - return (ls->pdf > 0.0f); - } - - const int lamp = -prim - 1; - - if (UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) { - return false; - } - - return light_sample<in_volume_segment>(kg, lamp, randu, randv, P, path_flag, ls); -} - -ccl_device_inline bool light_distribution_sample_from_volume_segment(KernelGlobals kg, - float randu, - const float randv, - const float time, - const float3 P, - const int bounce, - const uint32_t path_flag, - ccl_private LightSample *ls) -{ - return light_distribution_sample<true>(kg, randu, randv, time, P, bounce, path_flag, ls); -} - -ccl_device_inline bool light_distribution_sample_from_position(KernelGlobals kg, - float randu, - const float randv, - const float time, - const float3 P, - const int bounce, - const uint32_t path_flag, - ccl_private LightSample *ls) -{ - return light_distribution_sample<false>(kg, randu, randv, time, P, bounce, path_flag, ls); -} - -ccl_device_inline bool light_distribution_sample_new_position(KernelGlobals kg, - const float randu, - const float randv, - const float time, - const float3 P, - ccl_private LightSample *ls) -{ - /* Sample a new position on the same light, for volume sampling. */ - if (ls->type == LIGHT_TRIANGLE) { - triangle_light_sample<false>(kg, ls->prim, ls->object, randu, randv, time, ls, P); - return (ls->pdf > 0.0f); - } - else { - return light_sample<false>(kg, ls->lamp, randu, randv, P, 0, ls); - } -} - -CCL_NAMESPACE_END |