Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/render/light.cpp')
-rw-r--r--intern/cycles/render/light.cpp309
1 files changed, 309 insertions, 0 deletions
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
new file mode 100644
index 00000000000..74943fd0ff7
--- /dev/null
+++ b/intern/cycles/render/light.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "device.h"
+#include "light.h"
+#include "mesh.h"
+#include "object.h"
+#include "scene.h"
+#include "shader.h"
+
+#include "util_foreach.h"
+#include "util_progress.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Light */
+
+Light::Light()
+{
+ type = LIGHT_POINT;
+
+ co = make_float3(0.0f, 0.0f, 0.0f);
+
+ dir = make_float3(0.0f, 0.0f, 0.0f);
+ size = 0.0f;
+
+ axisu = make_float3(0.0f, 0.0f, 0.0f);
+ sizeu = 1.0f;
+ axisv = make_float3(0.0f, 0.0f, 0.0f);
+ sizev = 1.0f;
+
+ cast_shadow = true;
+ shader = 0;
+}
+
+void Light::tag_update(Scene *scene)
+{
+ scene->light_manager->need_update = true;
+}
+
+/* Light Manager */
+
+LightManager::LightManager()
+{
+ need_update = true;
+}
+
+LightManager::~LightManager()
+{
+}
+
+void LightManager::device_update_distribution(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+{
+ /* option to always sample all point lights */
+ bool multi_light = false;
+
+ /* count */
+ size_t num_lights = scene->lights.size();
+ size_t num_triangles = 0;
+
+ foreach(Object *object, scene->objects) {
+ Mesh *mesh = object->mesh;
+ bool have_emission = false;
+
+ /* skip if we have no emission shaders */
+ foreach(uint sindex, mesh->used_shaders) {
+ Shader *shader = scene->shaders[sindex];
+
+ if(shader->sample_as_light && shader->has_surface_emission) {
+ have_emission = true;
+ break;
+ }
+ }
+
+ /* count triangles */
+ if(have_emission) {
+ for(size_t i = 0; i < mesh->triangles.size(); i++) {
+ Shader *shader = scene->shaders[mesh->shader[i]];
+
+ if(shader->sample_as_light && shader->has_surface_emission)
+ num_triangles++;
+ }
+ }
+ }
+
+ size_t num_distribution = num_triangles;
+
+ if(!multi_light)
+ num_distribution += num_lights;
+
+ /* emission area */
+ float4 *distribution = dscene->light_distribution.resize(num_distribution + 1);
+ float totarea = 0.0f;
+
+ /* triangles */
+ size_t offset = 0;
+ size_t j = 0;
+
+ foreach(Object *object, scene->objects) {
+ Mesh *mesh = object->mesh;
+ bool have_emission = false;
+
+ /* skip if we have no emission shaders */
+ foreach(uint sindex, mesh->used_shaders) {
+ Shader *shader = scene->shaders[sindex];
+
+ if(shader->sample_as_light && shader->has_surface_emission) {
+ have_emission = true;
+ break;
+ }
+ }
+
+ /* sum area */
+ if(have_emission) {
+ Transform tfm = object->tfm;
+ int object_id = (mesh->transform_applied)? -j-1: j;
+
+ for(size_t i = 0; i < mesh->triangles.size(); i++) {
+ Shader *shader = scene->shaders[mesh->shader[i]];
+
+ if(shader->sample_as_light && shader->has_surface_emission) {
+ distribution[offset].x = totarea;
+ distribution[offset].y = __int_as_float(i + mesh->tri_offset);
+ distribution[offset].z = 1.0f;
+ distribution[offset].w = __int_as_float(object_id);
+ offset++;
+
+ Mesh::Triangle t = mesh->triangles[i];
+ float3 p1 = transform(&tfm, mesh->verts[t.v[0]]);
+ float3 p2 = transform(&tfm, mesh->verts[t.v[1]]);
+ float3 p3 = transform(&tfm, mesh->verts[t.v[2]]);
+
+ totarea += triangle_area(p1, p2, p3);
+ }
+ }
+ }
+
+ if(progress.get_cancel()) return;
+
+ j++;
+ }
+
+ float trianglearea = totarea;
+
+ /* point lights */
+ if(!multi_light) {
+ float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f;
+
+ for(size_t i = 0; i < scene->lights.size(); i++, offset++) {
+ distribution[offset].x = totarea;
+ distribution[offset].y = __int_as_float(-i-1);
+ distribution[offset].z = 1.0f;
+ distribution[offset].w = scene->lights[i]->size;
+ totarea += lightarea;
+ }
+ }
+
+ /* normalize cumulative distribution functions */
+ distribution[num_distribution].x = totarea;
+ distribution[num_distribution].y = 0.0f;
+ distribution[num_distribution].z = 0.0f;
+ distribution[num_distribution].w = 0.0f;
+
+ if(totarea > 0.0f) {
+ for(size_t i = 0; i < num_distribution; i++)
+ distribution[i].x /= totarea;
+ distribution[num_distribution].x = 1.0f;
+ }
+
+ if(progress.get_cancel()) return;
+
+ /* update device */
+ KernelIntegrator *kintegrator = &dscene->data.integrator;
+ kintegrator->use_direct_light = (totarea > 0.0f) || (multi_light && num_lights);
+
+ if(kintegrator->use_direct_light) {
+ /* number of emissives */
+ kintegrator->num_distribution = (totarea > 0.0f)? num_distribution: 0;
+
+ /* precompute pdfs */
+ kintegrator->pdf_triangles = 0.0f;
+ kintegrator->pdf_lights = 0.0f;
+
+ if(multi_light) {
+ /* sample one of all triangles and all lights */
+ kintegrator->num_all_lights = num_lights;
+
+ if(trianglearea > 0.0f)
+ kintegrator->pdf_triangles = 1.0f/trianglearea;
+ if(num_lights)
+ kintegrator->pdf_lights = 1.0f;
+ }
+ else {
+ /* sample one, with 0.5 probability of light or triangle */
+ kintegrator->num_all_lights = 0;
+
+ if(trianglearea > 0.0f) {
+ kintegrator->pdf_triangles = 1.0f/trianglearea;
+ if(num_lights)
+ kintegrator->pdf_triangles *= 0.5f;
+ }
+
+ if(num_lights) {
+ kintegrator->pdf_lights = 1.0f/num_lights;
+ if(trianglearea > 0.0f)
+ kintegrator->pdf_lights *= 0.5f;
+ }
+ }
+
+ /* CDF */
+ device->tex_alloc("__light_distribution", dscene->light_distribution);
+ }
+ else
+ dscene->light_distribution.clear();
+}
+
+void LightManager::device_update_points(Device *device, DeviceScene *dscene, Scene *scene)
+{
+ if(scene->lights.size() == 0)
+ return;
+
+ float4 *light_data = dscene->light_data.resize(scene->lights.size()*LIGHT_SIZE);
+
+ for(size_t i = 0; i < scene->lights.size(); i++) {
+ Light *light = scene->lights[i];
+ float3 co = light->co;
+ float3 dir = normalize(light->dir);
+ int shader_id = scene->shader_manager->get_shader_id(scene->lights[i]->shader);
+
+ if(!light->cast_shadow)
+ shader_id &= ~SHADER_CAST_SHADOW;
+
+ if(light->type == LIGHT_POINT) {
+ shader_id &= ~SHADER_AREA_LIGHT;
+
+ light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
+ light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), light->size, 0.0f, 0.0f);
+ light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ light_data[i*LIGHT_SIZE + 3] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ else if(light->type == LIGHT_DISTANT) {
+ shader_id &= ~SHADER_AREA_LIGHT;
+
+ light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
+ light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), light->size, 0.0f, 0.0f);
+ light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ light_data[i*LIGHT_SIZE + 3] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ else if(light->type == LIGHT_AREA) {
+ float3 axisu = light->axisu*(light->sizeu*light->size);
+ float3 axisv = light->axisv*(light->sizev*light->size);
+
+ light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
+ light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
+ light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, axisv.x, axisv.y, axisv.z);
+ light_data[i*LIGHT_SIZE + 3] = make_float4(0.0f, dir.x, dir.y, dir.z);
+ }
+ }
+
+ device->tex_alloc("__light_data", dscene->light_data);
+}
+
+void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+{
+ if(!need_update)
+ return;
+
+ device_free(device, dscene);
+
+ device_update_points(device, dscene, scene);
+ if(progress.get_cancel()) return;
+
+ device_update_distribution(device, dscene, scene, progress);
+ if(progress.get_cancel()) return;
+
+ need_update = false;
+}
+
+void LightManager::device_free(Device *device, DeviceScene *dscene)
+{
+ device->tex_free(dscene->light_distribution);
+ device->tex_free(dscene->light_data);
+
+ dscene->light_distribution.clear();
+ dscene->light_data.clear();
+}
+
+void LightManager::tag_update(Scene *scene)
+{
+ need_update = true;
+}
+
+CCL_NAMESPACE_END
+