Blender V2.61 - r43446
|
00001 /* 00002 * Copyright 2011, Blender Foundation. 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 CCL_NAMESPACE_BEGIN 00020 00021 typedef struct LightSample { 00022 float3 P; 00023 float3 D; 00024 float3 Ng; 00025 float t; 00026 int object; 00027 int prim; 00028 int shader; 00029 } LightSample; 00030 00031 /* Regular Light */ 00032 00033 __device float3 disk_light_sample(float3 v, float randu, float randv) 00034 { 00035 float3 ru, rv; 00036 00037 make_orthonormals(v, &ru, &rv); 00038 to_unit_disk(&randu, &randv); 00039 00040 return ru*randu + rv*randv; 00041 } 00042 00043 __device float3 distant_light_sample(float3 D, float size, float randu, float randv) 00044 { 00045 return normalize(D + disk_light_sample(D, randu, randv)*size); 00046 } 00047 00048 __device float3 sphere_light_sample(float3 P, float3 center, float size, float randu, float randv) 00049 { 00050 return disk_light_sample(normalize(P - center), randu, randv)*size; 00051 } 00052 00053 __device float3 area_light_sample(float3 axisu, float3 axisv, float randu, float randv) 00054 { 00055 randu = randu - 0.5f; 00056 randv = randv - 0.5f; 00057 00058 return axisu*randu + axisv*randv; 00059 } 00060 00061 __device void regular_light_sample(KernelGlobals *kg, int point, 00062 float randu, float randv, float3 P, LightSample *ls) 00063 { 00064 float4 data0 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 0); 00065 float4 data1 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 1); 00066 00067 LightType type = (LightType)__float_as_int(data0.x); 00068 00069 if(type == LIGHT_DISTANT) { 00070 /* distant light */ 00071 float3 D = make_float3(data0.y, data0.z, data0.w); 00072 float size = data1.y; 00073 00074 if(size > 0.0f) 00075 D = distant_light_sample(D, size, randu, randv); 00076 00077 ls->P = D; 00078 ls->Ng = D; 00079 ls->D = -D; 00080 ls->t = FLT_MAX; 00081 } 00082 else { 00083 ls->P = make_float3(data0.y, data0.z, data0.w); 00084 00085 if(type == LIGHT_POINT) { 00086 float size = data1.y; 00087 00088 /* sphere light */ 00089 if(size > 0.0f) 00090 ls->P += sphere_light_sample(P, ls->P, size, randu, randv); 00091 00092 ls->Ng = normalize(P - ls->P); 00093 } 00094 else { 00095 /* area light */ 00096 float4 data2 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 2); 00097 float4 data3 = kernel_tex_fetch(__light_data, point*LIGHT_SIZE + 3); 00098 00099 float3 axisu = make_float3(data1.y, data1.z, data2.w); 00100 float3 axisv = make_float3(data2.y, data2.z, data2.w); 00101 float3 D = make_float3(data3.y, data3.z, data3.w); 00102 00103 ls->P += area_light_sample(axisu, axisv, randu, randv); 00104 ls->Ng = D; 00105 } 00106 00107 ls->t = 0.0f; 00108 } 00109 00110 ls->shader = __float_as_int(data1.x); 00111 ls->object = ~0; 00112 ls->prim = ~0; 00113 } 00114 00115 __device float regular_light_pdf(KernelGlobals *kg, 00116 const float3 Ng, const float3 I, float t) 00117 { 00118 float pdf = kernel_data.integrator.pdf_lights; 00119 00120 if(t == FLT_MAX) 00121 return pdf; 00122 00123 float cos_pi = dot(Ng, I); 00124 00125 if(cos_pi <= 0.0f) 00126 return 0.0f; 00127 00128 return t*t*pdf/cos_pi; 00129 } 00130 00131 /* Triangle Light */ 00132 00133 __device void triangle_light_sample(KernelGlobals *kg, int prim, int object, 00134 float randu, float randv, LightSample *ls) 00135 { 00136 /* triangle, so get position, normal, shader */ 00137 ls->P = triangle_sample_MT(kg, prim, randu, randv); 00138 ls->Ng = triangle_normal_MT(kg, prim, &ls->shader); 00139 ls->object = object; 00140 ls->prim = prim; 00141 ls->t = 0.0f; 00142 00143 #ifdef __INSTANCING__ 00144 /* instance transform */ 00145 if(ls->object >= 0) { 00146 object_position_transform(kg, ls->object, &ls->P); 00147 object_normal_transform(kg, ls->object, &ls->Ng); 00148 } 00149 #endif 00150 } 00151 00152 __device float triangle_light_pdf(KernelGlobals *kg, 00153 const float3 Ng, const float3 I, float t) 00154 { 00155 float cos_pi = fabsf(dot(Ng, I)); 00156 00157 if(cos_pi == 0.0f) 00158 return 0.0f; 00159 00160 return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi; 00161 } 00162 00163 /* Light Distribution */ 00164 00165 __device int light_distribution_sample(KernelGlobals *kg, float randt) 00166 { 00167 /* this is basically std::upper_bound as used by pbrt, to find a point light or 00168 triangle to emit from, proportional to area. a good improvement would be to 00169 also sample proportional to power, though it's not so well defined with 00170 OSL shaders. */ 00171 int first = 0; 00172 int len = kernel_data.integrator.num_distribution + 1; 00173 00174 while(len > 0) { 00175 int half_len = len >> 1; 00176 int middle = first + half_len; 00177 00178 if(randt < kernel_tex_fetch(__light_distribution, middle).x) { 00179 len = half_len; 00180 } 00181 else { 00182 first = middle + 1; 00183 len = len - half_len - 1; 00184 } 00185 } 00186 00187 first = max(0, first-1); 00188 kernel_assert(first >= 0 && first < kernel_data.integrator.num_distribution); 00189 00190 return first; 00191 } 00192 00193 /* Generic Light */ 00194 00195 __device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float3 P, LightSample *ls) 00196 { 00197 /* sample index */ 00198 int index = light_distribution_sample(kg, randt); 00199 00200 /* fetch light data */ 00201 float4 l = kernel_tex_fetch(__light_distribution, index); 00202 int prim = __float_as_int(l.y); 00203 00204 if(prim >= 0) { 00205 int object = __float_as_int(l.w); 00206 triangle_light_sample(kg, prim, object, randu, randv, ls); 00207 } 00208 else { 00209 int point = -prim-1; 00210 regular_light_sample(kg, point, randu, randv, P, ls); 00211 } 00212 00213 /* compute incoming direction and distance */ 00214 if(ls->t != FLT_MAX) 00215 ls->D = normalize_len(ls->P - P, &ls->t); 00216 } 00217 00218 __device float light_sample_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t) 00219 { 00220 float pdf; 00221 00222 if(ls->prim != ~0) 00223 pdf = triangle_light_pdf(kg, ls->Ng, I, t); 00224 else 00225 pdf = regular_light_pdf(kg, ls->Ng, I, t); 00226 00227 return pdf; 00228 } 00229 00230 __device void light_select(KernelGlobals *kg, int index, float randu, float randv, float3 P, LightSample *ls) 00231 { 00232 regular_light_sample(kg, index, randu, randv, P, ls); 00233 } 00234 00235 __device float light_select_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t) 00236 { 00237 return regular_light_pdf(kg, ls->Ng, I, t); 00238 } 00239 00240 CCL_NAMESPACE_END 00241