2 * Copyright 2011, Blender Foundation.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 typedef struct LightSample {
33 __device float3 disk_light_sample(float3 v, float randu, float randv)
37 make_orthonormals(v, &ru, &rv);
38 to_unit_disk(&randu, &randv);
40 return ru*randu + rv*randv;
43 __device float3 distant_light_sample(float3 D, float size, float randu, float randv)
45 return normalize(D + disk_light_sample(D, randu, randv)*size);
48 __device float3 sphere_light_sample(float3 P, float3 center, float size, float randu, float randv)
50 return disk_light_sample(normalize(P - center), randu, randv)*size;
53 __device float3 area_light_sample(float3 axisu, float3 axisv, float randu, float randv)
58 return axisu*randu + axisv*randv;
61 __device void regular_light_sample(KernelGlobals *kg, int point,
62 float randu, float randv, float3 P, LightSample *ls)
64 float4 data0 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 0);
65 float4 data1 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 1);
67 LightType type = (LightType)__float_as_int(data0.x);
69 if(type == LIGHT_DISTANT) {
71 float3 D = make_float3(data0.y, data0.z, data0.w);
75 D = distant_light_sample(D, size, randu, randv);
83 ls->P = make_float3(data0.y, data0.z, data0.w);
85 if(type == LIGHT_POINT) {
90 ls->P += sphere_light_sample(P, ls->P, size, randu, randv);
92 ls->Ng = normalize(P - ls->P);
96 float4 data2 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 2);
97 float4 data3 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 3);
99 float3 axisu = make_float3(data1.y, data1.z, data2.w);
100 float3 axisv = make_float3(data2.y, data2.z, data2.w);
101 float3 D = make_float3(data3.y, data3.z, data3.w);
103 ls->P += area_light_sample(axisu, axisv, randu, randv);
110 ls->shader = __float_as_int(data1.x);
115 __device float regular_light_pdf(KernelGlobals *kg,
116 const float3 Ng, const float3 I, float t)
118 float pdf = kernel_data.integrator.pdf_lights;
123 float cos_pi = fabsf(dot(Ng, I));
128 return t*t*pdf/cos_pi;
133 __device void triangle_light_sample(KernelGlobals *kg, int prim, int object,
134 float randu, float randv, LightSample *ls)
136 /* triangle, so get position, normal, shader */
137 ls->P = triangle_sample_MT(kg, prim, randu, randv);
138 ls->Ng = triangle_normal_MT(kg, prim, &ls->shader);
143 #ifdef __INSTANCING__
144 /* instance transform */
145 if(ls->object >= 0) {
146 object_position_transform(kg, ls->object, &ls->P);
147 object_normal_transform(kg, ls->object, &ls->Ng);
152 __device float triangle_light_pdf(KernelGlobals *kg,
153 const float3 Ng, const float3 I, float t)
155 float cos_pi = fabsf(dot(Ng, I));
160 return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi;
163 /* Light Distribution */
165 __device int light_distribution_sample(KernelGlobals *kg, float randt)
167 /* this is basically std::upper_bound as used by pbrt, to find a point light or
168 triangle to emit from, proportional to area. a good improvement would be to
169 also sample proportional to power, though it's not so well defined with
172 int len = kernel_data.integrator.num_distribution + 1;
175 int half_len = len >> 1;
176 int middle = first + half_len;
178 if(randt < kernel_tex_fetch(__light_distribution, middle).x) {
183 len = len - half_len - 1;
187 first = max(0, first-1);
188 kernel_assert(first >= 0 && first < kernel_data.integrator.num_distribution);
195 __device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float3 P, LightSample *ls)
198 int index = light_distribution_sample(kg, randt);
200 /* fetch light data */
201 float4 l = kernel_tex_fetch(__light_distribution, index);
202 int prim = __float_as_int(l.y);
205 int object = __float_as_int(l.w);
206 triangle_light_sample(kg, prim, object, randu, randv, ls);
210 regular_light_sample(kg, point, randu, randv, P, ls);
213 /* compute incoming direction and distance */
215 ls->D = normalize_len(ls->P - P, &ls->t);
218 __device float light_sample_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t)
223 pdf = triangle_light_pdf(kg, ls->Ng, I, t);
225 pdf = regular_light_pdf(kg, ls->Ng, I, t);
230 __device void light_select(KernelGlobals *kg, int index, float randu, float randv, float3 P, LightSample *ls)
232 regular_light_sample(kg, index, randu, randv, P, ls);
235 __device float light_select_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t)
237 return regular_light_pdf(kg, ls->Ng, I, t);