Blender V2.61 - r43446

light.cpp

Go to the documentation of this file.
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 #include "device.h"
00020 #include "light.h"
00021 #include "mesh.h"
00022 #include "object.h"
00023 #include "scene.h"
00024 #include "shader.h"
00025 
00026 #include "util_foreach.h"
00027 #include "util_progress.h"
00028 
00029 CCL_NAMESPACE_BEGIN
00030 
00031 /* Light */
00032 
00033 Light::Light()
00034 {
00035     type = LIGHT_POINT;
00036 
00037     co = make_float3(0.0f, 0.0f, 0.0f);
00038 
00039     dir = make_float3(0.0f, 0.0f, 0.0f);
00040     size = 0.0f;
00041 
00042     axisu = make_float3(0.0f, 0.0f, 0.0f);
00043     sizeu = 1.0f;
00044     axisv = make_float3(0.0f, 0.0f, 0.0f);
00045     sizev = 1.0f;
00046 
00047     cast_shadow = true;
00048     shader = 0;
00049 }
00050 
00051 void Light::tag_update(Scene *scene)
00052 {
00053     scene->light_manager->need_update = true;
00054 }
00055 
00056 /* Light Manager */
00057 
00058 LightManager::LightManager()
00059 {
00060     need_update = true;
00061 }
00062 
00063 LightManager::~LightManager()
00064 {
00065 }
00066 
00067 void LightManager::device_update_distribution(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
00068 {
00069     /* option to always sample all point lights */
00070     bool multi_light = false;
00071 
00072     /* count */
00073     size_t num_lights = scene->lights.size();
00074     size_t num_triangles = 0;
00075 
00076     foreach(Object *object, scene->objects) {
00077         Mesh *mesh = object->mesh;
00078         bool have_emission = false;
00079 
00080         /* skip if we have no emission shaders */
00081         foreach(uint sindex, mesh->used_shaders) {
00082             Shader *shader = scene->shaders[sindex];
00083 
00084             if(shader->sample_as_light && shader->has_surface_emission) {
00085                 have_emission = true;
00086                 break;
00087             }
00088         }
00089 
00090         /* count triangles */
00091         if(have_emission) {
00092             for(size_t i = 0; i < mesh->triangles.size(); i++) {
00093                 Shader *shader = scene->shaders[mesh->shader[i]];
00094 
00095                 if(shader->sample_as_light && shader->has_surface_emission)
00096                     num_triangles++;
00097             }
00098         }
00099     }
00100 
00101     size_t num_distribution = num_triangles;
00102 
00103     if(!multi_light)
00104         num_distribution += num_lights;
00105 
00106     /* emission area */
00107     float4 *distribution = dscene->light_distribution.resize(num_distribution + 1);
00108     float totarea = 0.0f;
00109 
00110     /* triangles */
00111     size_t offset = 0;
00112     size_t j = 0;
00113 
00114     foreach(Object *object, scene->objects) {
00115         Mesh *mesh = object->mesh;
00116         bool have_emission = false;
00117 
00118         /* skip if we have no emission shaders */
00119         foreach(uint sindex, mesh->used_shaders) {
00120             Shader *shader = scene->shaders[sindex];
00121 
00122             if(shader->sample_as_light && shader->has_surface_emission) {
00123                 have_emission = true;
00124                 break;
00125             }
00126         }
00127 
00128         /* sum area */
00129         if(have_emission) {
00130             Transform tfm = object->tfm;
00131             int object_id = (mesh->transform_applied)? -j-1: j;
00132 
00133             for(size_t i = 0; i < mesh->triangles.size(); i++) {
00134                 Shader *shader = scene->shaders[mesh->shader[i]];
00135 
00136                 if(shader->sample_as_light && shader->has_surface_emission) {
00137                     distribution[offset].x = totarea;
00138                     distribution[offset].y = __int_as_float(i + mesh->tri_offset);
00139                     distribution[offset].z = 1.0f;
00140                     distribution[offset].w = __int_as_float(object_id);
00141                     offset++;
00142 
00143                     Mesh::Triangle t = mesh->triangles[i];
00144                     float3 p1 = transform(&tfm, mesh->verts[t.v[0]]);
00145                     float3 p2 = transform(&tfm, mesh->verts[t.v[1]]);
00146                     float3 p3 = transform(&tfm, mesh->verts[t.v[2]]);
00147 
00148                     totarea += triangle_area(p1, p2, p3);
00149                 }
00150             }
00151         }
00152 
00153         if(progress.get_cancel()) return;
00154 
00155         j++;
00156     }
00157 
00158     float trianglearea = totarea;
00159 
00160     /* point lights */
00161     if(!multi_light) {
00162         float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f;
00163 
00164         for(size_t i = 0; i < scene->lights.size(); i++, offset++) {
00165             distribution[offset].x = totarea;
00166             distribution[offset].y = __int_as_float(-i-1);
00167             distribution[offset].z = 1.0f;
00168             distribution[offset].w = scene->lights[i]->size;
00169             totarea += lightarea;
00170         }
00171     }
00172 
00173     /* normalize cumulative distribution functions */
00174     distribution[num_distribution].x = totarea;
00175     distribution[num_distribution].y = 0.0f;
00176     distribution[num_distribution].z = 0.0f;
00177     distribution[num_distribution].w = 0.0f;
00178 
00179     if(totarea > 0.0f) {
00180         for(size_t i = 0; i < num_distribution; i++)
00181             distribution[i].x /= totarea;
00182         distribution[num_distribution].x = 1.0f;
00183     }
00184 
00185     if(progress.get_cancel()) return;
00186 
00187     /* update device */
00188     KernelIntegrator *kintegrator = &dscene->data.integrator;
00189     kintegrator->use_direct_light = (totarea > 0.0f) || (multi_light && num_lights);
00190 
00191     if(kintegrator->use_direct_light) {
00192         /* number of emissives */
00193         kintegrator->num_distribution = (totarea > 0.0f)? num_distribution: 0;
00194 
00195         /* precompute pdfs */
00196         kintegrator->pdf_triangles = 0.0f;
00197         kintegrator->pdf_lights = 0.0f;
00198 
00199         if(multi_light) {
00200             /* sample one of all triangles and all lights */
00201             kintegrator->num_all_lights = num_lights;
00202 
00203             if(trianglearea > 0.0f)
00204                 kintegrator->pdf_triangles = 1.0f/trianglearea;
00205             if(num_lights)
00206                 kintegrator->pdf_lights = 1.0f;
00207         }
00208         else {
00209             /* sample one, with 0.5 probability of light or triangle */
00210             kintegrator->num_all_lights = 0;
00211 
00212             if(trianglearea > 0.0f) {
00213                 kintegrator->pdf_triangles = 1.0f/trianglearea;
00214                 if(num_lights)
00215                     kintegrator->pdf_triangles *= 0.5f;
00216             }
00217 
00218             if(num_lights) {
00219                 kintegrator->pdf_lights = 1.0f/num_lights;
00220                 if(trianglearea > 0.0f)
00221                     kintegrator->pdf_lights *= 0.5f;
00222             }
00223         }
00224 
00225         /* CDF */
00226         device->tex_alloc("__light_distribution", dscene->light_distribution);
00227     }
00228     else
00229         dscene->light_distribution.clear();
00230 }
00231 
00232 void LightManager::device_update_points(Device *device, DeviceScene *dscene, Scene *scene)
00233 {
00234     if(scene->lights.size() == 0)
00235         return;
00236 
00237     float4 *light_data = dscene->light_data.resize(scene->lights.size()*LIGHT_SIZE);
00238 
00239     for(size_t i = 0; i < scene->lights.size(); i++) {
00240         Light *light = scene->lights[i];
00241         float3 co = light->co;
00242         float3 dir = normalize(light->dir);
00243         int shader_id = scene->shader_manager->get_shader_id(scene->lights[i]->shader);
00244 
00245         if(!light->cast_shadow)
00246             shader_id &= ~SHADER_CAST_SHADOW;
00247 
00248         if(light->type == LIGHT_POINT) {
00249             shader_id &= ~SHADER_AREA_LIGHT;
00250 
00251             light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
00252             light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), light->size, 0.0f, 0.0f);
00253             light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
00254             light_data[i*LIGHT_SIZE + 3] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
00255         }
00256         else if(light->type == LIGHT_DISTANT) {
00257             shader_id &= ~SHADER_AREA_LIGHT;
00258 
00259             light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
00260             light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), light->size, 0.0f, 0.0f);
00261             light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
00262             light_data[i*LIGHT_SIZE + 3] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
00263         }
00264         else if(light->type == LIGHT_AREA) {
00265             float3 axisu = light->axisu*(light->sizeu*light->size);
00266             float3 axisv = light->axisv*(light->sizev*light->size);
00267 
00268             light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
00269             light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
00270             light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, axisv.x, axisv.y, axisv.z);
00271             light_data[i*LIGHT_SIZE + 3] = make_float4(0.0f, dir.x, dir.y, dir.z);
00272         }
00273     }
00274     
00275     device->tex_alloc("__light_data", dscene->light_data);
00276 }
00277 
00278 void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
00279 {
00280     if(!need_update)
00281         return;
00282 
00283     device_free(device, dscene);
00284 
00285     device_update_points(device, dscene, scene);
00286     if(progress.get_cancel()) return;
00287 
00288     device_update_distribution(device, dscene, scene, progress);
00289     if(progress.get_cancel()) return;
00290 
00291     need_update = false;
00292 }
00293 
00294 void LightManager::device_free(Device *device, DeviceScene *dscene)
00295 {
00296     device->tex_free(dscene->light_distribution);
00297     device->tex_free(dscene->light_data);
00298 
00299     dscene->light_distribution.clear();
00300     dscene->light_data.clear();
00301 }
00302 
00303 void LightManager::tag_update(Scene *scene)
00304 {
00305     need_update = true;
00306 }
00307 
00308 CCL_NAMESPACE_END
00309