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.cpp1792
1 files changed, 903 insertions, 889 deletions
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index 56d60adf71d..d4c233e3bb3 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -34,1002 +34,1016 @@
CCL_NAMESPACE_BEGIN
-static void shade_background_pixels(Device *device, DeviceScene *dscene, int width, int height, vector<float3>& pixels, Progress& progress)
+static void shade_background_pixels(Device *device,
+ DeviceScene *dscene,
+ int width,
+ int height,
+ vector<float3> &pixels,
+ Progress &progress)
{
- /* create input */
- device_vector<uint4> d_input(device, "background_input", MEM_READ_ONLY);
- device_vector<float4> d_output(device, "background_output", MEM_READ_WRITE);
-
- uint4 *d_input_data = d_input.alloc(width*height);
-
- for(int y = 0; y < height; y++) {
- for(int x = 0; x < width; x++) {
- float u = (x + 0.5f)/width;
- float v = (y + 0.5f)/height;
-
- uint4 in = make_uint4(__float_as_int(u), __float_as_int(v), 0, 0);
- d_input_data[x + y*width] = in;
- }
- }
-
- /* compute on device */
- d_output.alloc(width*height);
- d_output.zero_to_device();
- d_input.copy_to_device();
-
- device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
-
- DeviceTask main_task(DeviceTask::SHADER);
- main_task.shader_input = d_input.device_pointer;
- main_task.shader_output = d_output.device_pointer;
- main_task.shader_eval_type = SHADER_EVAL_BACKGROUND;
- main_task.shader_x = 0;
- main_task.shader_w = width*height;
- main_task.num_samples = 1;
- main_task.get_cancel = function_bind(&Progress::get_cancel, &progress);
-
- /* disabled splitting for now, there's an issue with multi-GPU mem_copy_from */
- list<DeviceTask> split_tasks;
- main_task.split(split_tasks, 1, 128*128);
-
- foreach(DeviceTask& task, split_tasks) {
- device->task_add(task);
- device->task_wait();
- d_output.copy_from_device(task.shader_x, 1, task.shader_w);
- }
-
- d_input.free();
-
- float4 *d_output_data = d_output.data();
-
- pixels.resize(width*height);
-
- for(int y = 0; y < height; y++) {
- for(int x = 0; x < width; x++) {
- pixels[y*width + x].x = d_output_data[y*width + x].x;
- pixels[y*width + x].y = d_output_data[y*width + x].y;
- pixels[y*width + x].z = d_output_data[y*width + x].z;
- }
- }
-
- d_output.free();
+ /* create input */
+ device_vector<uint4> d_input(device, "background_input", MEM_READ_ONLY);
+ device_vector<float4> d_output(device, "background_output", MEM_READ_WRITE);
+
+ uint4 *d_input_data = d_input.alloc(width * height);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ float u = (x + 0.5f) / width;
+ float v = (y + 0.5f) / height;
+
+ uint4 in = make_uint4(__float_as_int(u), __float_as_int(v), 0, 0);
+ d_input_data[x + y * width] = in;
+ }
+ }
+
+ /* compute on device */
+ d_output.alloc(width * height);
+ d_output.zero_to_device();
+ d_input.copy_to_device();
+
+ device->const_copy_to("__data", &dscene->data, sizeof(dscene->data));
+
+ DeviceTask main_task(DeviceTask::SHADER);
+ main_task.shader_input = d_input.device_pointer;
+ main_task.shader_output = d_output.device_pointer;
+ main_task.shader_eval_type = SHADER_EVAL_BACKGROUND;
+ main_task.shader_x = 0;
+ main_task.shader_w = width * height;
+ main_task.num_samples = 1;
+ main_task.get_cancel = function_bind(&Progress::get_cancel, &progress);
+
+ /* disabled splitting for now, there's an issue with multi-GPU mem_copy_from */
+ list<DeviceTask> split_tasks;
+ main_task.split(split_tasks, 1, 128 * 128);
+
+ foreach (DeviceTask &task, split_tasks) {
+ device->task_add(task);
+ device->task_wait();
+ d_output.copy_from_device(task.shader_x, 1, task.shader_w);
+ }
+
+ d_input.free();
+
+ float4 *d_output_data = d_output.data();
+
+ pixels.resize(width * height);
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ pixels[y * width + x].x = d_output_data[y * width + x].x;
+ pixels[y * width + x].y = d_output_data[y * width + x].y;
+ pixels[y * width + x].z = d_output_data[y * width + x].z;
+ }
+ }
+
+ d_output.free();
}
/* Light */
NODE_DEFINE(Light)
{
- NodeType* type = NodeType::add("light", create);
+ NodeType *type = NodeType::add("light", create);
- static NodeEnum type_enum;
- type_enum.insert("point", LIGHT_POINT);
- type_enum.insert("distant", LIGHT_DISTANT);
- type_enum.insert("background", LIGHT_BACKGROUND);
- type_enum.insert("area", LIGHT_AREA);
- type_enum.insert("spot", LIGHT_SPOT);
- SOCKET_ENUM(type, "Type", type_enum, LIGHT_POINT);
+ static NodeEnum type_enum;
+ type_enum.insert("point", LIGHT_POINT);
+ type_enum.insert("distant", LIGHT_DISTANT);
+ type_enum.insert("background", LIGHT_BACKGROUND);
+ type_enum.insert("area", LIGHT_AREA);
+ type_enum.insert("spot", LIGHT_SPOT);
+ SOCKET_ENUM(type, "Type", type_enum, LIGHT_POINT);
- SOCKET_POINT(co, "Co", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_POINT(co, "Co", make_float3(0.0f, 0.0f, 0.0f));
- SOCKET_VECTOR(dir, "Dir", make_float3(0.0f, 0.0f, 0.0f));
- SOCKET_FLOAT(size, "Size", 0.0f);
+ SOCKET_VECTOR(dir, "Dir", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_FLOAT(size, "Size", 0.0f);
- SOCKET_VECTOR(axisu, "Axis U", make_float3(0.0f, 0.0f, 0.0f));
- SOCKET_FLOAT(sizeu, "Size U", 1.0f);
- SOCKET_VECTOR(axisv, "Axis V", make_float3(0.0f, 0.0f, 0.0f));
- SOCKET_FLOAT(sizev, "Size V", 1.0f);
- SOCKET_BOOLEAN(round, "Round", false);
+ SOCKET_VECTOR(axisu, "Axis U", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_FLOAT(sizeu, "Size U", 1.0f);
+ SOCKET_VECTOR(axisv, "Axis V", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_FLOAT(sizev, "Size V", 1.0f);
+ SOCKET_BOOLEAN(round, "Round", false);
- SOCKET_INT(map_resolution, "Map Resolution", 0);
+ SOCKET_INT(map_resolution, "Map Resolution", 0);
- SOCKET_FLOAT(spot_angle, "Spot Angle", M_PI_4_F);
- SOCKET_FLOAT(spot_smooth, "Spot Smooth", 0.0f);
+ SOCKET_FLOAT(spot_angle, "Spot Angle", M_PI_4_F);
+ SOCKET_FLOAT(spot_smooth, "Spot Smooth", 0.0f);
- SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
+ SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
- SOCKET_BOOLEAN(cast_shadow, "Cast Shadow", true);
- SOCKET_BOOLEAN(use_mis, "Use Mis", false);
- SOCKET_BOOLEAN(use_diffuse, "Use Diffuse", true);
- SOCKET_BOOLEAN(use_glossy, "Use Glossy", true);
- SOCKET_BOOLEAN(use_transmission, "Use Transmission", true);
- SOCKET_BOOLEAN(use_scatter, "Use Scatter", true);
+ SOCKET_BOOLEAN(cast_shadow, "Cast Shadow", true);
+ SOCKET_BOOLEAN(use_mis, "Use Mis", false);
+ SOCKET_BOOLEAN(use_diffuse, "Use Diffuse", true);
+ SOCKET_BOOLEAN(use_glossy, "Use Glossy", true);
+ SOCKET_BOOLEAN(use_transmission, "Use Transmission", true);
+ SOCKET_BOOLEAN(use_scatter, "Use Scatter", true);
- SOCKET_INT(samples, "Samples", 1);
- SOCKET_INT(max_bounces, "Max Bounces", 1024);
- SOCKET_UINT(random_id, "Random ID", 0);
+ SOCKET_INT(samples, "Samples", 1);
+ SOCKET_INT(max_bounces, "Max Bounces", 1024);
+ SOCKET_UINT(random_id, "Random ID", 0);
- SOCKET_BOOLEAN(is_portal, "Is Portal", false);
- SOCKET_BOOLEAN(is_enabled, "Is Enabled", true);
+ SOCKET_BOOLEAN(is_portal, "Is Portal", false);
+ SOCKET_BOOLEAN(is_enabled, "Is Enabled", true);
- SOCKET_NODE(shader, "Shader", &Shader::node_type);
+ SOCKET_NODE(shader, "Shader", &Shader::node_type);
- return type;
+ return type;
}
-Light::Light()
-: Node(node_type)
+Light::Light() : Node(node_type)
{
}
void Light::tag_update(Scene *scene)
{
- scene->light_manager->need_update = true;
+ scene->light_manager->need_update = true;
}
bool Light::has_contribution(Scene *scene)
{
- if(is_portal) {
- return false;
- }
- if(type == LIGHT_BACKGROUND) {
- return true;
- }
- return (shader) ? shader->has_surface_emission : scene->default_light->has_surface_emission;
+ if (is_portal) {
+ return false;
+ }
+ if (type == LIGHT_BACKGROUND) {
+ return true;
+ }
+ return (shader) ? shader->has_surface_emission : scene->default_light->has_surface_emission;
}
/* Light Manager */
LightManager::LightManager()
{
- need_update = true;
- use_light_visibility = false;
+ need_update = true;
+ use_light_visibility = false;
}
LightManager::~LightManager()
{
- foreach(IESSlot *slot, ies_slots) {
- delete slot;
- }
+ foreach (IESSlot *slot, ies_slots) {
+ delete slot;
+ }
}
bool LightManager::has_background_light(Scene *scene)
{
- foreach(Light *light, scene->lights) {
- if(light->type == LIGHT_BACKGROUND && light->is_enabled) {
- return true;
- }
- }
- return false;
+ foreach (Light *light, scene->lights) {
+ if (light->type == LIGHT_BACKGROUND && light->is_enabled) {
+ return true;
+ }
+ }
+ return false;
}
void LightManager::disable_ineffective_light(Scene *scene)
{
- /* Make all lights enabled by default, and perform some preliminary checks
- * needed for finer-tuning of settings (for example, check whether we've
- * got portals or not).
- */
- bool has_portal = false, has_background = false;
- foreach(Light *light, scene->lights) {
- light->is_enabled = light->has_contribution(scene);
- has_portal |= light->is_portal;
- has_background |= light->type == LIGHT_BACKGROUND;
- }
-
- if(has_background) {
- /* Ignore background light if:
- * - If unsupported on a device
- * - If we don't need it (no HDRs etc.)
- */
- Shader *shader = (scene->background->shader) ? scene->background->shader : scene->default_background;
- bool disable_mis = !(has_portal || shader->has_surface_spatial_varying);
- if(disable_mis) {
- VLOG(1) << "Background MIS has been disabled.\n";
- foreach(Light *light, scene->lights) {
- if(light->type == LIGHT_BACKGROUND) {
- light->is_enabled = false;
- }
- }
- }
- }
+ /* Make all lights enabled by default, and perform some preliminary checks
+ * needed for finer-tuning of settings (for example, check whether we've
+ * got portals or not).
+ */
+ bool has_portal = false, has_background = false;
+ foreach (Light *light, scene->lights) {
+ light->is_enabled = light->has_contribution(scene);
+ has_portal |= light->is_portal;
+ has_background |= light->type == LIGHT_BACKGROUND;
+ }
+
+ if (has_background) {
+ /* Ignore background light if:
+ * - If unsupported on a device
+ * - If we don't need it (no HDRs etc.)
+ */
+ Shader *shader = (scene->background->shader) ? scene->background->shader :
+ scene->default_background;
+ bool disable_mis = !(has_portal || shader->has_surface_spatial_varying);
+ if (disable_mis) {
+ VLOG(1) << "Background MIS has been disabled.\n";
+ foreach (Light *light, scene->lights) {
+ if (light->type == LIGHT_BACKGROUND) {
+ light->is_enabled = false;
+ }
+ }
+ }
+ }
}
-bool LightManager::object_usable_as_light(Object *object) {
- Mesh *mesh = object->mesh;
- /* Skip objects with NaNs */
- if(!object->bounds.valid()) {
- return false;
- }
- /* Skip if we are not visible for BSDFs. */
- if(!(object->visibility & (PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY|PATH_RAY_TRANSMIT))) {
- return false;
- }
- /* Skip if we have no emission shaders. */
- /* TODO(sergey): Ideally we want to avoid such duplicated loop, since it'll
- * iterate all mesh shaders twice (when counting and when calculating
- * triangle area.
- */
- foreach(const Shader *shader, mesh->used_shaders) {
- if(shader->use_mis && shader->has_surface_emission) {
- return true;
- }
- }
- return false;
+bool LightManager::object_usable_as_light(Object *object)
+{
+ Mesh *mesh = object->mesh;
+ /* Skip objects with NaNs */
+ if (!object->bounds.valid()) {
+ return false;
+ }
+ /* Skip if we are not visible for BSDFs. */
+ if (!(object->visibility & (PATH_RAY_DIFFUSE | PATH_RAY_GLOSSY | PATH_RAY_TRANSMIT))) {
+ return false;
+ }
+ /* Skip if we have no emission shaders. */
+ /* TODO(sergey): Ideally we want to avoid such duplicated loop, since it'll
+ * iterate all mesh shaders twice (when counting and when calculating
+ * triangle area.
+ */
+ foreach (const Shader *shader, mesh->used_shaders) {
+ if (shader->use_mis && shader->has_surface_emission) {
+ return true;
+ }
+ }
+ return false;
}
-void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Scene *scene, Progress& progress)
+void LightManager::device_update_distribution(Device *,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
{
- progress.set_status("Updating Lights", "Computing distribution");
-
- /* count */
- size_t num_lights = 0;
- size_t num_portals = 0;
- size_t num_background_lights = 0;
- size_t num_triangles = 0;
-
- bool background_mis = false;
-
- foreach(Light *light, scene->lights) {
- if(light->is_enabled) {
- num_lights++;
- }
- if(light->is_portal) {
- num_portals++;
- }
- }
-
- foreach(Object *object, scene->objects) {
- if(progress.get_cancel()) return;
-
- if(!object_usable_as_light(object)) {
- continue;
- }
- /* Count triangles. */
- Mesh *mesh = object->mesh;
- size_t mesh_num_triangles = mesh->num_triangles();
- for(size_t i = 0; i < mesh_num_triangles; i++) {
- int shader_index = mesh->shader[i];
- Shader *shader = (shader_index < mesh->used_shaders.size())
- ? mesh->used_shaders[shader_index]
- : scene->default_surface;
-
- if(shader->use_mis && shader->has_surface_emission) {
- num_triangles++;
- }
- }
- }
-
- size_t num_distribution = num_triangles + num_lights;
- VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
-
- /* emission area */
- KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1);
- float totarea = 0.0f;
-
- /* triangles */
- size_t offset = 0;
- int j = 0;
-
- foreach(Object *object, scene->objects) {
- if(progress.get_cancel()) return;
-
- if(!object_usable_as_light(object)) {
- j++;
- continue;
- }
- /* Sum area. */
- Mesh *mesh = object->mesh;
- bool transform_applied = mesh->transform_applied;
- Transform tfm = object->tfm;
- int object_id = j;
- int shader_flag = 0;
-
- if(!(object->visibility & PATH_RAY_DIFFUSE)) {
- shader_flag |= SHADER_EXCLUDE_DIFFUSE;
- use_light_visibility = true;
- }
- if(!(object->visibility & PATH_RAY_GLOSSY)) {
- shader_flag |= SHADER_EXCLUDE_GLOSSY;
- use_light_visibility = true;
- }
- if(!(object->visibility & PATH_RAY_TRANSMIT)) {
- shader_flag |= SHADER_EXCLUDE_TRANSMIT;
- use_light_visibility = true;
- }
- if(!(object->visibility & PATH_RAY_VOLUME_SCATTER)) {
- shader_flag |= SHADER_EXCLUDE_SCATTER;
- use_light_visibility = true;
- }
-
- size_t mesh_num_triangles = mesh->num_triangles();
- for(size_t i = 0; i < mesh_num_triangles; i++) {
- int shader_index = mesh->shader[i];
- Shader *shader = (shader_index < mesh->used_shaders.size())
- ? mesh->used_shaders[shader_index]
- : scene->default_surface;
-
- if(shader->use_mis && shader->has_surface_emission) {
- distribution[offset].totarea = totarea;
- distribution[offset].prim = i + mesh->tri_offset;
- distribution[offset].mesh_light.shader_flag = shader_flag;
- distribution[offset].mesh_light.object_id = object_id;
- offset++;
-
- Mesh::Triangle t = mesh->get_triangle(i);
- if(!t.valid(&mesh->verts[0])) {
- continue;
- }
- float3 p1 = mesh->verts[t.v[0]];
- float3 p2 = mesh->verts[t.v[1]];
- float3 p3 = mesh->verts[t.v[2]];
-
- if(!transform_applied) {
- p1 = transform_point(&tfm, p1);
- p2 = transform_point(&tfm, p2);
- p3 = transform_point(&tfm, p3);
- }
-
- totarea += triangle_area(p1, p2, p3);
- }
- }
-
- j++;
- }
-
- float trianglearea = totarea;
-
- /* point lights */
- float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f;
- bool use_lamp_mis = false;
-
- int light_index = 0;
- foreach(Light *light, scene->lights) {
- if(!light->is_enabled)
- continue;
-
- distribution[offset].totarea = totarea;
- distribution[offset].prim = ~light_index;
- distribution[offset].lamp.pad = 1.0f;
- distribution[offset].lamp.size = light->size;
- totarea += lightarea;
-
- if(light->size > 0.0f && light->use_mis)
- use_lamp_mis = true;
- if(light->type == LIGHT_BACKGROUND) {
- num_background_lights++;
- background_mis = light->use_mis;
- }
-
- light_index++;
- offset++;
- }
-
- /* normalize cumulative distribution functions */
- distribution[num_distribution].totarea = totarea;
- distribution[num_distribution].prim = 0.0f;
- distribution[num_distribution].lamp.pad = 0.0f;
- distribution[num_distribution].lamp.size = 0.0f;
-
- if(totarea > 0.0f) {
- for(size_t i = 0; i < num_distribution; i++)
- distribution[i].totarea /= totarea;
- distribution[num_distribution].totarea = 1.0f;
- }
-
- if(progress.get_cancel()) return;
-
- /* update device */
- KernelIntegrator *kintegrator = &dscene->data.integrator;
- KernelFilm *kfilm = &dscene->data.film;
- kintegrator->use_direct_light = (totarea > 0.0f);
-
- if(kintegrator->use_direct_light) {
- /* number of emissives */
- kintegrator->num_distribution = num_distribution;
-
- /* precompute pdfs */
- kintegrator->pdf_triangles = 0.0f;
- kintegrator->pdf_lights = 0.0f;
-
- /* sample one, with 0.5 probability of light or triangle */
- kintegrator->num_all_lights = num_lights;
-
- 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;
- }
-
- kintegrator->use_lamp_mis = use_lamp_mis;
-
- /* bit of an ugly hack to compensate for emitting triangles influencing
- * amount of samples we get for this pass */
- kfilm->pass_shadow_scale = 1.0f;
-
- if(kintegrator->pdf_triangles != 0.0f)
- kfilm->pass_shadow_scale *= 0.5f;
-
- if(num_background_lights < num_lights)
- kfilm->pass_shadow_scale *= (float)(num_lights - num_background_lights)/(float)num_lights;
-
- /* CDF */
- dscene->light_distribution.copy_to_device();
-
- /* Portals */
- if(num_portals > 0) {
- kintegrator->portal_offset = light_index;
- kintegrator->num_portals = num_portals;
- kintegrator->portal_pdf = background_mis? 0.5f: 1.0f;
- }
- else {
- kintegrator->num_portals = 0;
- kintegrator->portal_offset = 0;
- kintegrator->portal_pdf = 0.0f;
- }
- }
- else {
- dscene->light_distribution.free();
-
- kintegrator->num_distribution = 0;
- kintegrator->num_all_lights = 0;
- kintegrator->pdf_triangles = 0.0f;
- kintegrator->pdf_lights = 0.0f;
- kintegrator->use_lamp_mis = false;
- kintegrator->num_portals = 0;
- kintegrator->portal_offset = 0;
- kintegrator->portal_pdf = 0.0f;
-
- kfilm->pass_shadow_scale = 1.0f;
- }
+ progress.set_status("Updating Lights", "Computing distribution");
+
+ /* count */
+ size_t num_lights = 0;
+ size_t num_portals = 0;
+ size_t num_background_lights = 0;
+ size_t num_triangles = 0;
+
+ bool background_mis = false;
+
+ foreach (Light *light, scene->lights) {
+ if (light->is_enabled) {
+ num_lights++;
+ }
+ if (light->is_portal) {
+ num_portals++;
+ }
+ }
+
+ foreach (Object *object, scene->objects) {
+ if (progress.get_cancel())
+ return;
+
+ if (!object_usable_as_light(object)) {
+ continue;
+ }
+ /* Count triangles. */
+ Mesh *mesh = object->mesh;
+ size_t mesh_num_triangles = mesh->num_triangles();
+ for (size_t i = 0; i < mesh_num_triangles; i++) {
+ int shader_index = mesh->shader[i];
+ Shader *shader = (shader_index < mesh->used_shaders.size()) ?
+ mesh->used_shaders[shader_index] :
+ scene->default_surface;
+
+ if (shader->use_mis && shader->has_surface_emission) {
+ num_triangles++;
+ }
+ }
+ }
+
+ size_t num_distribution = num_triangles + num_lights;
+ VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
+
+ /* emission area */
+ KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1);
+ float totarea = 0.0f;
+
+ /* triangles */
+ size_t offset = 0;
+ int j = 0;
+
+ foreach (Object *object, scene->objects) {
+ if (progress.get_cancel())
+ return;
+
+ if (!object_usable_as_light(object)) {
+ j++;
+ continue;
+ }
+ /* Sum area. */
+ Mesh *mesh = object->mesh;
+ bool transform_applied = mesh->transform_applied;
+ Transform tfm = object->tfm;
+ int object_id = j;
+ int shader_flag = 0;
+
+ if (!(object->visibility & PATH_RAY_DIFFUSE)) {
+ shader_flag |= SHADER_EXCLUDE_DIFFUSE;
+ use_light_visibility = true;
+ }
+ if (!(object->visibility & PATH_RAY_GLOSSY)) {
+ shader_flag |= SHADER_EXCLUDE_GLOSSY;
+ use_light_visibility = true;
+ }
+ if (!(object->visibility & PATH_RAY_TRANSMIT)) {
+ shader_flag |= SHADER_EXCLUDE_TRANSMIT;
+ use_light_visibility = true;
+ }
+ if (!(object->visibility & PATH_RAY_VOLUME_SCATTER)) {
+ shader_flag |= SHADER_EXCLUDE_SCATTER;
+ use_light_visibility = true;
+ }
+
+ size_t mesh_num_triangles = mesh->num_triangles();
+ for (size_t i = 0; i < mesh_num_triangles; i++) {
+ int shader_index = mesh->shader[i];
+ Shader *shader = (shader_index < mesh->used_shaders.size()) ?
+ mesh->used_shaders[shader_index] :
+ scene->default_surface;
+
+ if (shader->use_mis && shader->has_surface_emission) {
+ distribution[offset].totarea = totarea;
+ distribution[offset].prim = i + mesh->tri_offset;
+ distribution[offset].mesh_light.shader_flag = shader_flag;
+ distribution[offset].mesh_light.object_id = object_id;
+ offset++;
+
+ Mesh::Triangle t = mesh->get_triangle(i);
+ if (!t.valid(&mesh->verts[0])) {
+ continue;
+ }
+ float3 p1 = mesh->verts[t.v[0]];
+ float3 p2 = mesh->verts[t.v[1]];
+ float3 p3 = mesh->verts[t.v[2]];
+
+ if (!transform_applied) {
+ p1 = transform_point(&tfm, p1);
+ p2 = transform_point(&tfm, p2);
+ p3 = transform_point(&tfm, p3);
+ }
+
+ totarea += triangle_area(p1, p2, p3);
+ }
+ }
+
+ j++;
+ }
+
+ float trianglearea = totarea;
+
+ /* point lights */
+ float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f;
+ bool use_lamp_mis = false;
+
+ int light_index = 0;
+ foreach (Light *light, scene->lights) {
+ if (!light->is_enabled)
+ continue;
+
+ distribution[offset].totarea = totarea;
+ distribution[offset].prim = ~light_index;
+ distribution[offset].lamp.pad = 1.0f;
+ distribution[offset].lamp.size = light->size;
+ totarea += lightarea;
+
+ if (light->size > 0.0f && light->use_mis)
+ use_lamp_mis = true;
+ if (light->type == LIGHT_BACKGROUND) {
+ num_background_lights++;
+ background_mis = light->use_mis;
+ }
+
+ light_index++;
+ offset++;
+ }
+
+ /* normalize cumulative distribution functions */
+ distribution[num_distribution].totarea = totarea;
+ distribution[num_distribution].prim = 0.0f;
+ distribution[num_distribution].lamp.pad = 0.0f;
+ distribution[num_distribution].lamp.size = 0.0f;
+
+ if (totarea > 0.0f) {
+ for (size_t i = 0; i < num_distribution; i++)
+ distribution[i].totarea /= totarea;
+ distribution[num_distribution].totarea = 1.0f;
+ }
+
+ if (progress.get_cancel())
+ return;
+
+ /* update device */
+ KernelIntegrator *kintegrator = &dscene->data.integrator;
+ KernelFilm *kfilm = &dscene->data.film;
+ kintegrator->use_direct_light = (totarea > 0.0f);
+
+ if (kintegrator->use_direct_light) {
+ /* number of emissives */
+ kintegrator->num_distribution = num_distribution;
+
+ /* precompute pdfs */
+ kintegrator->pdf_triangles = 0.0f;
+ kintegrator->pdf_lights = 0.0f;
+
+ /* sample one, with 0.5 probability of light or triangle */
+ kintegrator->num_all_lights = num_lights;
+
+ 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;
+ }
+
+ kintegrator->use_lamp_mis = use_lamp_mis;
+
+ /* bit of an ugly hack to compensate for emitting triangles influencing
+ * amount of samples we get for this pass */
+ kfilm->pass_shadow_scale = 1.0f;
+
+ if (kintegrator->pdf_triangles != 0.0f)
+ kfilm->pass_shadow_scale *= 0.5f;
+
+ if (num_background_lights < num_lights)
+ kfilm->pass_shadow_scale *= (float)(num_lights - num_background_lights) / (float)num_lights;
+
+ /* CDF */
+ dscene->light_distribution.copy_to_device();
+
+ /* Portals */
+ if (num_portals > 0) {
+ kintegrator->portal_offset = light_index;
+ kintegrator->num_portals = num_portals;
+ kintegrator->portal_pdf = background_mis ? 0.5f : 1.0f;
+ }
+ else {
+ kintegrator->num_portals = 0;
+ kintegrator->portal_offset = 0;
+ kintegrator->portal_pdf = 0.0f;
+ }
+ }
+ else {
+ dscene->light_distribution.free();
+
+ kintegrator->num_distribution = 0;
+ kintegrator->num_all_lights = 0;
+ kintegrator->pdf_triangles = 0.0f;
+ kintegrator->pdf_lights = 0.0f;
+ kintegrator->use_lamp_mis = false;
+ kintegrator->num_portals = 0;
+ kintegrator->portal_offset = 0;
+ kintegrator->portal_pdf = 0.0f;
+
+ kfilm->pass_shadow_scale = 1.0f;
+ }
}
-static void background_cdf(int start,
- int end,
- int res_x,
- int res_y,
- const vector<float3> *pixels,
- float2 *cond_cdf)
+static void background_cdf(
+ int start, int end, int res_x, int res_y, const vector<float3> *pixels, float2 *cond_cdf)
{
- int cdf_width = res_x+1;
- /* Conditional CDFs (rows, U direction). */
- for(int i = start; i < end; i++) {
- float sin_theta = sinf(M_PI_F * (i + 0.5f) / res_y);
- float3 env_color = (*pixels)[i * res_x];
- float ave_luminance = average(env_color);
-
- cond_cdf[i * cdf_width].x = ave_luminance * sin_theta;
- cond_cdf[i * cdf_width].y = 0.0f;
-
- for(int j = 1; j < res_x; j++) {
- env_color = (*pixels)[i * res_x + j];
- ave_luminance = average(env_color);
-
- cond_cdf[i * cdf_width + j].x = ave_luminance * sin_theta;
- cond_cdf[i * cdf_width + j].y = cond_cdf[i * cdf_width + j - 1].y + cond_cdf[i * cdf_width + j - 1].x / res_x;
- }
-
- float cdf_total = cond_cdf[i * cdf_width + res_x - 1].y + cond_cdf[i * cdf_width + res_x - 1].x / res_x;
- float cdf_total_inv = 1.0f / cdf_total;
-
- /* stuff the total into the brightness value for the last entry, because
- * we are going to normalize the CDFs to 0.0 to 1.0 afterwards */
- cond_cdf[i * cdf_width + res_x].x = cdf_total;
-
- if(cdf_total > 0.0f)
- for(int j = 1; j < res_x; j++)
- cond_cdf[i * cdf_width + j].y *= cdf_total_inv;
-
- cond_cdf[i * cdf_width + res_x].y = 1.0f;
- }
+ int cdf_width = res_x + 1;
+ /* Conditional CDFs (rows, U direction). */
+ for (int i = start; i < end; i++) {
+ float sin_theta = sinf(M_PI_F * (i + 0.5f) / res_y);
+ float3 env_color = (*pixels)[i * res_x];
+ float ave_luminance = average(env_color);
+
+ cond_cdf[i * cdf_width].x = ave_luminance * sin_theta;
+ cond_cdf[i * cdf_width].y = 0.0f;
+
+ for (int j = 1; j < res_x; j++) {
+ env_color = (*pixels)[i * res_x + j];
+ ave_luminance = average(env_color);
+
+ cond_cdf[i * cdf_width + j].x = ave_luminance * sin_theta;
+ cond_cdf[i * cdf_width + j].y = cond_cdf[i * cdf_width + j - 1].y +
+ cond_cdf[i * cdf_width + j - 1].x / res_x;
+ }
+
+ float cdf_total = cond_cdf[i * cdf_width + res_x - 1].y +
+ cond_cdf[i * cdf_width + res_x - 1].x / res_x;
+ float cdf_total_inv = 1.0f / cdf_total;
+
+ /* stuff the total into the brightness value for the last entry, because
+ * we are going to normalize the CDFs to 0.0 to 1.0 afterwards */
+ cond_cdf[i * cdf_width + res_x].x = cdf_total;
+
+ if (cdf_total > 0.0f)
+ for (int j = 1; j < res_x; j++)
+ cond_cdf[i * cdf_width + j].y *= cdf_total_inv;
+
+ cond_cdf[i * cdf_width + res_x].y = 1.0f;
+ }
}
void LightManager::device_update_background(Device *device,
DeviceScene *dscene,
Scene *scene,
- Progress& progress)
+ Progress &progress)
{
- KernelIntegrator *kintegrator = &dscene->data.integrator;
- Light *background_light = NULL;
-
- /* find background light */
- foreach(Light *light, scene->lights) {
- if(light->type == LIGHT_BACKGROUND) {
- background_light = light;
- break;
- }
- }
-
- /* no background light found, signal renderer to skip sampling */
- if(!background_light || !background_light->is_enabled) {
- kintegrator->pdf_background_res_x = 0;
- kintegrator->pdf_background_res_y = 0;
- return;
- }
-
- progress.set_status("Updating Lights", "Importance map");
-
- assert(kintegrator->use_direct_light);
-
- /* get the resolution from the light's size (we stuff it in there) */
- int2 res = make_int2(background_light->map_resolution, background_light->map_resolution/2);
- /* If the resolution isn't set manually, try to find an environment texture. */
- if(res.x == 0) {
- Shader *shader = (scene->background->shader) ? scene->background->shader : scene->default_background;
- foreach(ShaderNode *node, shader->graph->nodes) {
- if(node->type == EnvironmentTextureNode::node_type) {
- EnvironmentTextureNode *env = (EnvironmentTextureNode*) node;
- ImageMetaData metadata;
- if(env->image_manager && env->image_manager->get_image_metadata(env->slot, metadata)) {
- res.x = max(res.x, metadata.width);
- res.y = max(res.y, metadata.height);
- }
- }
- }
- if(res.x > 0 && res.y > 0) {
- VLOG(2) << "Automatically set World MIS resolution to " << res.x << " by " << res.y << "\n";
- }
- }
- /* If it's still unknown, just use the default. */
- if(res.x == 0 || res.y == 0) {
- res = make_int2(1024, 512);
- VLOG(2) << "Setting World MIS resolution to default\n";
- }
- kintegrator->pdf_background_res_x = res.x;
- kintegrator->pdf_background_res_y = res.y;
-
- vector<float3> pixels;
- shade_background_pixels(device, dscene, res.x, res.y, pixels, progress);
-
- if(progress.get_cancel())
- return;
-
- /* build row distributions and column distribution for the infinite area environment light */
- int cdf_width = res.x+1;
- float2 *marg_cdf = dscene->light_background_marginal_cdf.alloc(res.y + 1);
- float2 *cond_cdf = dscene->light_background_conditional_cdf.alloc(cdf_width * res.y);
-
- double time_start = time_dt();
- if(max(res.x, res.y) < 512) {
- /* Small enough resolution, faster to do single-threaded. */
- background_cdf(0, res.y, res.x, res.y, &pixels, cond_cdf);
- }
- else {
- /* Threaded evaluation for large resolution. */
- const int num_blocks = TaskScheduler::num_threads();
- const int chunk_size = res.y / num_blocks;
- int start_row = 0;
- TaskPool pool;
- for(int i = 0; i < num_blocks; ++i) {
- const int current_chunk_size =
- (i != num_blocks - 1) ? chunk_size
- : (res.y - i * chunk_size);
- pool.push(function_bind(&background_cdf,
- start_row, start_row + current_chunk_size,
- res.x,
- res.y,
- &pixels,
- cond_cdf));
- start_row += current_chunk_size;
- }
- pool.wait_work();
- }
-
- /* marginal CDFs (column, V direction, sum of rows) */
- marg_cdf[0].x = cond_cdf[res.x].x;
- marg_cdf[0].y = 0.0f;
-
- for(int i = 1; i < res.y; i++) {
- marg_cdf[i].x = cond_cdf[i * cdf_width + res.x].x;
- marg_cdf[i].y = marg_cdf[i - 1].y + marg_cdf[i - 1].x / res.y;
- }
-
- float cdf_total = marg_cdf[res.y - 1].y + marg_cdf[res.y - 1].x / res.y;
- marg_cdf[res.y].x = cdf_total;
-
- if(cdf_total > 0.0f)
- for(int i = 1; i < res.y; i++)
- marg_cdf[i].y /= cdf_total;
-
- marg_cdf[res.y].y = 1.0f;
-
- VLOG(2) << "Background MIS build time " << time_dt() - time_start << "\n";
-
- /* update device */
- dscene->light_background_marginal_cdf.copy_to_device();
- dscene->light_background_conditional_cdf.copy_to_device();
+ KernelIntegrator *kintegrator = &dscene->data.integrator;
+ Light *background_light = NULL;
+
+ /* find background light */
+ foreach (Light *light, scene->lights) {
+ if (light->type == LIGHT_BACKGROUND) {
+ background_light = light;
+ break;
+ }
+ }
+
+ /* no background light found, signal renderer to skip sampling */
+ if (!background_light || !background_light->is_enabled) {
+ kintegrator->pdf_background_res_x = 0;
+ kintegrator->pdf_background_res_y = 0;
+ return;
+ }
+
+ progress.set_status("Updating Lights", "Importance map");
+
+ assert(kintegrator->use_direct_light);
+
+ /* get the resolution from the light's size (we stuff it in there) */
+ int2 res = make_int2(background_light->map_resolution, background_light->map_resolution / 2);
+ /* If the resolution isn't set manually, try to find an environment texture. */
+ if (res.x == 0) {
+ Shader *shader = (scene->background->shader) ? scene->background->shader :
+ scene->default_background;
+ foreach (ShaderNode *node, shader->graph->nodes) {
+ if (node->type == EnvironmentTextureNode::node_type) {
+ EnvironmentTextureNode *env = (EnvironmentTextureNode *)node;
+ ImageMetaData metadata;
+ if (env->image_manager && env->image_manager->get_image_metadata(env->slot, metadata)) {
+ res.x = max(res.x, metadata.width);
+ res.y = max(res.y, metadata.height);
+ }
+ }
+ }
+ if (res.x > 0 && res.y > 0) {
+ VLOG(2) << "Automatically set World MIS resolution to " << res.x << " by " << res.y << "\n";
+ }
+ }
+ /* If it's still unknown, just use the default. */
+ if (res.x == 0 || res.y == 0) {
+ res = make_int2(1024, 512);
+ VLOG(2) << "Setting World MIS resolution to default\n";
+ }
+ kintegrator->pdf_background_res_x = res.x;
+ kintegrator->pdf_background_res_y = res.y;
+
+ vector<float3> pixels;
+ shade_background_pixels(device, dscene, res.x, res.y, pixels, progress);
+
+ if (progress.get_cancel())
+ return;
+
+ /* build row distributions and column distribution for the infinite area environment light */
+ int cdf_width = res.x + 1;
+ float2 *marg_cdf = dscene->light_background_marginal_cdf.alloc(res.y + 1);
+ float2 *cond_cdf = dscene->light_background_conditional_cdf.alloc(cdf_width * res.y);
+
+ double time_start = time_dt();
+ if (max(res.x, res.y) < 512) {
+ /* Small enough resolution, faster to do single-threaded. */
+ background_cdf(0, res.y, res.x, res.y, &pixels, cond_cdf);
+ }
+ else {
+ /* Threaded evaluation for large resolution. */
+ const int num_blocks = TaskScheduler::num_threads();
+ const int chunk_size = res.y / num_blocks;
+ int start_row = 0;
+ TaskPool pool;
+ for (int i = 0; i < num_blocks; ++i) {
+ const int current_chunk_size = (i != num_blocks - 1) ? chunk_size : (res.y - i * chunk_size);
+ pool.push(function_bind(&background_cdf,
+ start_row,
+ start_row + current_chunk_size,
+ res.x,
+ res.y,
+ &pixels,
+ cond_cdf));
+ start_row += current_chunk_size;
+ }
+ pool.wait_work();
+ }
+
+ /* marginal CDFs (column, V direction, sum of rows) */
+ marg_cdf[0].x = cond_cdf[res.x].x;
+ marg_cdf[0].y = 0.0f;
+
+ for (int i = 1; i < res.y; i++) {
+ marg_cdf[i].x = cond_cdf[i * cdf_width + res.x].x;
+ marg_cdf[i].y = marg_cdf[i - 1].y + marg_cdf[i - 1].x / res.y;
+ }
+
+ float cdf_total = marg_cdf[res.y - 1].y + marg_cdf[res.y - 1].x / res.y;
+ marg_cdf[res.y].x = cdf_total;
+
+ if (cdf_total > 0.0f)
+ for (int i = 1; i < res.y; i++)
+ marg_cdf[i].y /= cdf_total;
+
+ marg_cdf[res.y].y = 1.0f;
+
+ VLOG(2) << "Background MIS build time " << time_dt() - time_start << "\n";
+
+ /* update device */
+ dscene->light_background_marginal_cdf.copy_to_device();
+ dscene->light_background_conditional_cdf.copy_to_device();
}
-void LightManager::device_update_points(Device *,
- DeviceScene *dscene,
- Scene *scene)
+void LightManager::device_update_points(Device *, DeviceScene *dscene, Scene *scene)
{
- int num_scene_lights = scene->lights.size();
-
- int num_lights = 0;
- foreach(Light *light, scene->lights) {
- if(light->is_enabled || light->is_portal) {
- num_lights++;
- }
- }
-
- KernelLight *klights = dscene->lights.alloc(num_lights);
-
- if(num_lights == 0) {
- VLOG(1) << "No effective light, ignoring points update.";
- return;
- }
-
- int light_index = 0;
-
- foreach(Light *light, scene->lights) {
- if(!light->is_enabled) {
- continue;
- }
-
- float3 co = light->co;
- Shader *shader = (light->shader) ? light->shader : scene->default_light;
- int shader_id = scene->shader_manager->get_shader_id(shader);
- int samples = light->samples;
- int max_bounces = light->max_bounces;
- float random = (float)light->random_id * (1.0f/(float)0xFFFFFFFF);
-
- if(!light->cast_shadow)
- shader_id &= ~SHADER_CAST_SHADOW;
-
- if(!light->use_diffuse) {
- shader_id |= SHADER_EXCLUDE_DIFFUSE;
- use_light_visibility = true;
- }
- if(!light->use_glossy) {
- shader_id |= SHADER_EXCLUDE_GLOSSY;
- use_light_visibility = true;
- }
- if(!light->use_transmission) {
- shader_id |= SHADER_EXCLUDE_TRANSMIT;
- use_light_visibility = true;
- }
- if(!light->use_scatter) {
- shader_id |= SHADER_EXCLUDE_SCATTER;
- use_light_visibility = true;
- }
-
- klights[light_index].type = light->type;
- klights[light_index].samples = samples;
-
- if(light->type == LIGHT_POINT) {
- shader_id &= ~SHADER_AREA_LIGHT;
-
- float radius = light->size;
- float invarea = (radius > 0.0f)? 1.0f/(M_PI_F*radius*radius): 1.0f;
-
- if(light->use_mis && radius > 0.0f)
- shader_id |= SHADER_USE_MIS;
-
- klights[light_index].co[0] = co.x;
- klights[light_index].co[1] = co.y;
- klights[light_index].co[2] = co.z;
-
- klights[light_index].spot.radius = radius;
- klights[light_index].spot.invarea = invarea;
- }
- else if(light->type == LIGHT_DISTANT) {
- shader_id &= ~SHADER_AREA_LIGHT;
-
- float radius = light->size;
- float angle = atanf(radius);
- float cosangle = cosf(angle);
- float area = M_PI_F*radius*radius;
- float invarea = (area > 0.0f)? 1.0f/area: 1.0f;
- float3 dir = light->dir;
-
- dir = safe_normalize(dir);
-
- if(light->use_mis && area > 0.0f)
- shader_id |= SHADER_USE_MIS;
-
- klights[light_index].co[0] = dir.x;
- klights[light_index].co[1] = dir.y;
- klights[light_index].co[2] = dir.z;
-
- klights[light_index].distant.invarea = invarea;
- klights[light_index].distant.radius = radius;
- klights[light_index].distant.cosangle = cosangle;
- }
- else if(light->type == LIGHT_BACKGROUND) {
- uint visibility = scene->background->visibility;
-
- shader_id &= ~SHADER_AREA_LIGHT;
- shader_id |= SHADER_USE_MIS;
-
- if(!(visibility & PATH_RAY_DIFFUSE)) {
- shader_id |= SHADER_EXCLUDE_DIFFUSE;
- use_light_visibility = true;
- }
- if(!(visibility & PATH_RAY_GLOSSY)) {
- shader_id |= SHADER_EXCLUDE_GLOSSY;
- use_light_visibility = true;
- }
- if(!(visibility & PATH_RAY_TRANSMIT)) {
- shader_id |= SHADER_EXCLUDE_TRANSMIT;
- use_light_visibility = true;
- }
- if(!(visibility & PATH_RAY_VOLUME_SCATTER)) {
- shader_id |= SHADER_EXCLUDE_SCATTER;
- use_light_visibility = true;
- }
- }
- else if(light->type == LIGHT_AREA) {
- float3 axisu = light->axisu*(light->sizeu*light->size);
- float3 axisv = light->axisv*(light->sizev*light->size);
- float area = len(axisu)*len(axisv);
- if(light->round) {
- area *= -M_PI_4_F;
- }
- float invarea = (area != 0.0f)? 1.0f/area: 1.0f;
- float3 dir = light->dir;
-
- dir = safe_normalize(dir);
-
- if(light->use_mis && area != 0.0f)
- shader_id |= SHADER_USE_MIS;
-
- klights[light_index].co[0] = co.x;
- klights[light_index].co[1] = co.y;
- klights[light_index].co[2] = co.z;
-
- klights[light_index].area.axisu[0] = axisu.x;
- klights[light_index].area.axisu[1] = axisu.y;
- klights[light_index].area.axisu[2] = axisu.z;
- klights[light_index].area.axisv[0] = axisv.x;
- klights[light_index].area.axisv[1] = axisv.y;
- klights[light_index].area.axisv[2] = axisv.z;
- klights[light_index].area.invarea = invarea;
- klights[light_index].area.dir[0] = dir.x;
- klights[light_index].area.dir[1] = dir.y;
- klights[light_index].area.dir[2] = dir.z;
- }
- else if(light->type == LIGHT_SPOT) {
- shader_id &= ~SHADER_AREA_LIGHT;
-
- float radius = light->size;
- float invarea = (radius > 0.0f)? 1.0f/(M_PI_F*radius*radius): 1.0f;
- float spot_angle = cosf(light->spot_angle*0.5f);
- float spot_smooth = (1.0f - spot_angle)*light->spot_smooth;
- float3 dir = light->dir;
-
- dir = safe_normalize(dir);
-
- if(light->use_mis && radius > 0.0f)
- shader_id |= SHADER_USE_MIS;
-
- klights[light_index].co[0] = co.x;
- klights[light_index].co[1] = co.y;
- klights[light_index].co[2] = co.z;
-
- klights[light_index].spot.radius = radius;
- klights[light_index].spot.invarea = invarea;
- klights[light_index].spot.spot_angle = spot_angle;
- klights[light_index].spot.spot_smooth = spot_smooth;
- klights[light_index].spot.dir[0] = dir.x;
- klights[light_index].spot.dir[1] = dir.y;
- klights[light_index].spot.dir[2] = dir.z;
- }
-
- klights[light_index].shader_id = shader_id;
-
- klights[light_index].max_bounces = max_bounces;
- klights[light_index].random = random;
-
- klights[light_index].tfm = light->tfm;
- klights[light_index].itfm = transform_inverse(light->tfm);
-
- light_index++;
- }
-
- /* TODO(sergey): Consider moving portals update to their own function
- * keeping this one more manageable.
- */
- foreach(Light *light, scene->lights) {
- if(!light->is_portal)
- continue;
- assert(light->type == LIGHT_AREA);
-
- float3 co = light->co;
- float3 axisu = light->axisu*(light->sizeu*light->size);
- float3 axisv = light->axisv*(light->sizev*light->size);
- float area = len(axisu)*len(axisv);
- if(light->round) {
- area *= -M_PI_4_F;
- }
- float invarea = (area != 0.0f)? 1.0f/area: 1.0f;
- float3 dir = light->dir;
-
- dir = safe_normalize(dir);
-
- klights[light_index].co[0] = co.x;
- klights[light_index].co[1] = co.y;
- klights[light_index].co[2] = co.z;
-
- klights[light_index].area.axisu[0] = axisu.x;
- klights[light_index].area.axisu[1] = axisu.y;
- klights[light_index].area.axisu[2] = axisu.z;
- klights[light_index].area.axisv[0] = axisv.x;
- klights[light_index].area.axisv[1] = axisv.y;
- klights[light_index].area.axisv[2] = axisv.z;
- klights[light_index].area.invarea = invarea;
- klights[light_index].area.dir[0] = dir.x;
- klights[light_index].area.dir[1] = dir.y;
- klights[light_index].area.dir[2] = dir.z;
- klights[light_index].tfm = light->tfm;
- klights[light_index].itfm = transform_inverse(light->tfm);
-
- light_index++;
- }
-
- VLOG(1) << "Number of lights sent to the device: " << light_index;
-
- VLOG(1) << "Number of lights without contribution: "
- << num_scene_lights - light_index;
-
- dscene->lights.copy_to_device();
+ int num_scene_lights = scene->lights.size();
+
+ int num_lights = 0;
+ foreach (Light *light, scene->lights) {
+ if (light->is_enabled || light->is_portal) {
+ num_lights++;
+ }
+ }
+
+ KernelLight *klights = dscene->lights.alloc(num_lights);
+
+ if (num_lights == 0) {
+ VLOG(1) << "No effective light, ignoring points update.";
+ return;
+ }
+
+ int light_index = 0;
+
+ foreach (Light *light, scene->lights) {
+ if (!light->is_enabled) {
+ continue;
+ }
+
+ float3 co = light->co;
+ Shader *shader = (light->shader) ? light->shader : scene->default_light;
+ int shader_id = scene->shader_manager->get_shader_id(shader);
+ int samples = light->samples;
+ int max_bounces = light->max_bounces;
+ float random = (float)light->random_id * (1.0f / (float)0xFFFFFFFF);
+
+ if (!light->cast_shadow)
+ shader_id &= ~SHADER_CAST_SHADOW;
+
+ if (!light->use_diffuse) {
+ shader_id |= SHADER_EXCLUDE_DIFFUSE;
+ use_light_visibility = true;
+ }
+ if (!light->use_glossy) {
+ shader_id |= SHADER_EXCLUDE_GLOSSY;
+ use_light_visibility = true;
+ }
+ if (!light->use_transmission) {
+ shader_id |= SHADER_EXCLUDE_TRANSMIT;
+ use_light_visibility = true;
+ }
+ if (!light->use_scatter) {
+ shader_id |= SHADER_EXCLUDE_SCATTER;
+ use_light_visibility = true;
+ }
+
+ klights[light_index].type = light->type;
+ klights[light_index].samples = samples;
+
+ if (light->type == LIGHT_POINT) {
+ shader_id &= ~SHADER_AREA_LIGHT;
+
+ float radius = light->size;
+ float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f;
+
+ if (light->use_mis && radius > 0.0f)
+ shader_id |= SHADER_USE_MIS;
+
+ klights[light_index].co[0] = co.x;
+ klights[light_index].co[1] = co.y;
+ klights[light_index].co[2] = co.z;
+
+ klights[light_index].spot.radius = radius;
+ klights[light_index].spot.invarea = invarea;
+ }
+ else if (light->type == LIGHT_DISTANT) {
+ shader_id &= ~SHADER_AREA_LIGHT;
+
+ float radius = light->size;
+ float angle = atanf(radius);
+ float cosangle = cosf(angle);
+ float area = M_PI_F * radius * radius;
+ float invarea = (area > 0.0f) ? 1.0f / area : 1.0f;
+ float3 dir = light->dir;
+
+ dir = safe_normalize(dir);
+
+ if (light->use_mis && area > 0.0f)
+ shader_id |= SHADER_USE_MIS;
+
+ klights[light_index].co[0] = dir.x;
+ klights[light_index].co[1] = dir.y;
+ klights[light_index].co[2] = dir.z;
+
+ klights[light_index].distant.invarea = invarea;
+ klights[light_index].distant.radius = radius;
+ klights[light_index].distant.cosangle = cosangle;
+ }
+ else if (light->type == LIGHT_BACKGROUND) {
+ uint visibility = scene->background->visibility;
+
+ shader_id &= ~SHADER_AREA_LIGHT;
+ shader_id |= SHADER_USE_MIS;
+
+ if (!(visibility & PATH_RAY_DIFFUSE)) {
+ shader_id |= SHADER_EXCLUDE_DIFFUSE;
+ use_light_visibility = true;
+ }
+ if (!(visibility & PATH_RAY_GLOSSY)) {
+ shader_id |= SHADER_EXCLUDE_GLOSSY;
+ use_light_visibility = true;
+ }
+ if (!(visibility & PATH_RAY_TRANSMIT)) {
+ shader_id |= SHADER_EXCLUDE_TRANSMIT;
+ use_light_visibility = true;
+ }
+ if (!(visibility & PATH_RAY_VOLUME_SCATTER)) {
+ shader_id |= SHADER_EXCLUDE_SCATTER;
+ use_light_visibility = true;
+ }
+ }
+ else if (light->type == LIGHT_AREA) {
+ float3 axisu = light->axisu * (light->sizeu * light->size);
+ float3 axisv = light->axisv * (light->sizev * light->size);
+ float area = len(axisu) * len(axisv);
+ if (light->round) {
+ area *= -M_PI_4_F;
+ }
+ float invarea = (area != 0.0f) ? 1.0f / area : 1.0f;
+ float3 dir = light->dir;
+
+ dir = safe_normalize(dir);
+
+ if (light->use_mis && area != 0.0f)
+ shader_id |= SHADER_USE_MIS;
+
+ klights[light_index].co[0] = co.x;
+ klights[light_index].co[1] = co.y;
+ klights[light_index].co[2] = co.z;
+
+ klights[light_index].area.axisu[0] = axisu.x;
+ klights[light_index].area.axisu[1] = axisu.y;
+ klights[light_index].area.axisu[2] = axisu.z;
+ klights[light_index].area.axisv[0] = axisv.x;
+ klights[light_index].area.axisv[1] = axisv.y;
+ klights[light_index].area.axisv[2] = axisv.z;
+ klights[light_index].area.invarea = invarea;
+ klights[light_index].area.dir[0] = dir.x;
+ klights[light_index].area.dir[1] = dir.y;
+ klights[light_index].area.dir[2] = dir.z;
+ }
+ else if (light->type == LIGHT_SPOT) {
+ shader_id &= ~SHADER_AREA_LIGHT;
+
+ float radius = light->size;
+ float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f;
+ float spot_angle = cosf(light->spot_angle * 0.5f);
+ float spot_smooth = (1.0f - spot_angle) * light->spot_smooth;
+ float3 dir = light->dir;
+
+ dir = safe_normalize(dir);
+
+ if (light->use_mis && radius > 0.0f)
+ shader_id |= SHADER_USE_MIS;
+
+ klights[light_index].co[0] = co.x;
+ klights[light_index].co[1] = co.y;
+ klights[light_index].co[2] = co.z;
+
+ klights[light_index].spot.radius = radius;
+ klights[light_index].spot.invarea = invarea;
+ klights[light_index].spot.spot_angle = spot_angle;
+ klights[light_index].spot.spot_smooth = spot_smooth;
+ klights[light_index].spot.dir[0] = dir.x;
+ klights[light_index].spot.dir[1] = dir.y;
+ klights[light_index].spot.dir[2] = dir.z;
+ }
+
+ klights[light_index].shader_id = shader_id;
+
+ klights[light_index].max_bounces = max_bounces;
+ klights[light_index].random = random;
+
+ klights[light_index].tfm = light->tfm;
+ klights[light_index].itfm = transform_inverse(light->tfm);
+
+ light_index++;
+ }
+
+ /* TODO(sergey): Consider moving portals update to their own function
+ * keeping this one more manageable.
+ */
+ foreach (Light *light, scene->lights) {
+ if (!light->is_portal)
+ continue;
+ assert(light->type == LIGHT_AREA);
+
+ float3 co = light->co;
+ float3 axisu = light->axisu * (light->sizeu * light->size);
+ float3 axisv = light->axisv * (light->sizev * light->size);
+ float area = len(axisu) * len(axisv);
+ if (light->round) {
+ area *= -M_PI_4_F;
+ }
+ float invarea = (area != 0.0f) ? 1.0f / area : 1.0f;
+ float3 dir = light->dir;
+
+ dir = safe_normalize(dir);
+
+ klights[light_index].co[0] = co.x;
+ klights[light_index].co[1] = co.y;
+ klights[light_index].co[2] = co.z;
+
+ klights[light_index].area.axisu[0] = axisu.x;
+ klights[light_index].area.axisu[1] = axisu.y;
+ klights[light_index].area.axisu[2] = axisu.z;
+ klights[light_index].area.axisv[0] = axisv.x;
+ klights[light_index].area.axisv[1] = axisv.y;
+ klights[light_index].area.axisv[2] = axisv.z;
+ klights[light_index].area.invarea = invarea;
+ klights[light_index].area.dir[0] = dir.x;
+ klights[light_index].area.dir[1] = dir.y;
+ klights[light_index].area.dir[2] = dir.z;
+ klights[light_index].tfm = light->tfm;
+ klights[light_index].itfm = transform_inverse(light->tfm);
+
+ light_index++;
+ }
+
+ VLOG(1) << "Number of lights sent to the device: " << light_index;
+
+ VLOG(1) << "Number of lights without contribution: " << num_scene_lights - light_index;
+
+ dscene->lights.copy_to_device();
}
-void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
+void LightManager::device_update(Device *device,
+ DeviceScene *dscene,
+ Scene *scene,
+ Progress &progress)
{
- if(!need_update)
- return;
+ if (!need_update)
+ return;
- VLOG(1) << "Total " << scene->lights.size() << " lights.";
+ VLOG(1) << "Total " << scene->lights.size() << " lights.";
- device_free(device, dscene);
+ device_free(device, dscene);
- use_light_visibility = false;
+ use_light_visibility = false;
- disable_ineffective_light(scene);
+ disable_ineffective_light(scene);
- device_update_points(device, dscene, scene);
- if(progress.get_cancel()) return;
+ device_update_points(device, dscene, scene);
+ if (progress.get_cancel())
+ return;
- device_update_distribution(device, dscene, scene, progress);
- if(progress.get_cancel()) return;
+ device_update_distribution(device, dscene, scene, progress);
+ if (progress.get_cancel())
+ return;
- device_update_background(device, dscene, scene, progress);
- if(progress.get_cancel()) return;
+ device_update_background(device, dscene, scene, progress);
+ if (progress.get_cancel())
+ return;
- device_update_ies(dscene);
- if(progress.get_cancel()) return;
+ device_update_ies(dscene);
+ if (progress.get_cancel())
+ return;
- if(use_light_visibility != scene->film->use_light_visibility) {
- scene->film->use_light_visibility = use_light_visibility;
- scene->film->tag_update(scene);
- }
+ if (use_light_visibility != scene->film->use_light_visibility) {
+ scene->film->use_light_visibility = use_light_visibility;
+ scene->film->tag_update(scene);
+ }
- need_update = false;
+ need_update = false;
}
void LightManager::device_free(Device *, DeviceScene *dscene)
{
- dscene->light_distribution.free();
- dscene->lights.free();
- dscene->light_background_marginal_cdf.free();
- dscene->light_background_conditional_cdf.free();
- dscene->ies_lights.free();
+ dscene->light_distribution.free();
+ dscene->lights.free();
+ dscene->light_background_marginal_cdf.free();
+ dscene->light_background_conditional_cdf.free();
+ dscene->ies_lights.free();
}
void LightManager::tag_update(Scene * /*scene*/)
{
- need_update = true;
+ need_update = true;
}
int LightManager::add_ies_from_file(ustring filename)
{
- string content;
+ string content;
- /* If the file can't be opened, call with an empty line */
- if(filename.empty() || !path_read_text(filename.c_str(), content)) {
- content = "\n";
- }
+ /* If the file can't be opened, call with an empty line */
+ if (filename.empty() || !path_read_text(filename.c_str(), content)) {
+ content = "\n";
+ }
- return add_ies(ustring(content));
+ return add_ies(ustring(content));
}
int LightManager::add_ies(ustring content)
{
- uint hash = hash_string(content.c_str());
-
- thread_scoped_lock ies_lock(ies_mutex);
-
- /* Check whether this IES already has a slot. */
- size_t slot;
- for(slot = 0; slot < ies_slots.size(); slot++) {
- if(ies_slots[slot]->hash == hash) {
- ies_slots[slot]->users++;
- return slot;
- }
- }
-
- /* Try to find an empty slot for the new IES. */
- for(slot = 0; slot < ies_slots.size(); slot++) {
- if(ies_slots[slot]->users == 0 && ies_slots[slot]->hash == 0) {
- break;
- }
- }
-
- /* If there's no free slot, add one. */
- if(slot == ies_slots.size()) {
- ies_slots.push_back(new IESSlot());
- }
-
- ies_slots[slot]->ies.load(content);
- ies_slots[slot]->users = 1;
- ies_slots[slot]->hash = hash;
-
- need_update = true;
-
- return slot;
+ uint hash = hash_string(content.c_str());
+
+ thread_scoped_lock ies_lock(ies_mutex);
+
+ /* Check whether this IES already has a slot. */
+ size_t slot;
+ for (slot = 0; slot < ies_slots.size(); slot++) {
+ if (ies_slots[slot]->hash == hash) {
+ ies_slots[slot]->users++;
+ return slot;
+ }
+ }
+
+ /* Try to find an empty slot for the new IES. */
+ for (slot = 0; slot < ies_slots.size(); slot++) {
+ if (ies_slots[slot]->users == 0 && ies_slots[slot]->hash == 0) {
+ break;
+ }
+ }
+
+ /* If there's no free slot, add one. */
+ if (slot == ies_slots.size()) {
+ ies_slots.push_back(new IESSlot());
+ }
+
+ ies_slots[slot]->ies.load(content);
+ ies_slots[slot]->users = 1;
+ ies_slots[slot]->hash = hash;
+
+ need_update = true;
+
+ return slot;
}
void LightManager::remove_ies(int slot)
{
- thread_scoped_lock ies_lock(ies_mutex);
+ thread_scoped_lock ies_lock(ies_mutex);
- if(slot < 0 || slot >= ies_slots.size()) {
- assert(false);
- return;
- }
+ if (slot < 0 || slot >= ies_slots.size()) {
+ assert(false);
+ return;
+ }
- assert(ies_slots[slot]->users > 0);
- ies_slots[slot]->users--;
+ assert(ies_slots[slot]->users > 0);
+ ies_slots[slot]->users--;
- /* If the slot has no more users, update the device to remove it. */
- need_update |= (ies_slots[slot]->users == 0);
+ /* If the slot has no more users, update the device to remove it. */
+ need_update |= (ies_slots[slot]->users == 0);
}
void LightManager::device_update_ies(DeviceScene *dscene)
{
- /* Clear empty slots. */
- foreach(IESSlot *slot, ies_slots) {
- if(slot->users == 0) {
- slot->hash = 0;
- slot->ies.clear();
- }
- }
-
- /* Shrink the slot table by removing empty slots at the end. */
- int slot_end;
- for(slot_end = ies_slots.size(); slot_end; slot_end--) {
- if(ies_slots[slot_end-1]->users > 0) {
- /* If the preceding slot has users, we found the new end of the table. */
- break;
- }
- else {
- /* The slot will be past the new end of the table, so free it. */
- delete ies_slots[slot_end-1];
- }
- }
- ies_slots.resize(slot_end);
-
- if(ies_slots.size() > 0) {
- int packed_size = 0;
- foreach(IESSlot *slot, ies_slots) {
- packed_size += slot->ies.packed_size();
- }
-
- /* ies_lights starts with an offset table that contains the offset of every slot,
- * or -1 if the slot is invalid.
- * Following that table, the packed valid IES lights are stored. */
- float *data = dscene->ies_lights.alloc(ies_slots.size() + packed_size);
-
- int offset = ies_slots.size();
- for(int i = 0; i < ies_slots.size(); i++) {
- int size = ies_slots[i]->ies.packed_size();
- if(size > 0) {
- data[i] = __int_as_float(offset);
- ies_slots[i]->ies.pack(data + offset);
- offset += size;
- }
- else {
- data[i] = __int_as_float(-1);
- }
- }
-
- dscene->ies_lights.copy_to_device();
- }
+ /* Clear empty slots. */
+ foreach (IESSlot *slot, ies_slots) {
+ if (slot->users == 0) {
+ slot->hash = 0;
+ slot->ies.clear();
+ }
+ }
+
+ /* Shrink the slot table by removing empty slots at the end. */
+ int slot_end;
+ for (slot_end = ies_slots.size(); slot_end; slot_end--) {
+ if (ies_slots[slot_end - 1]->users > 0) {
+ /* If the preceding slot has users, we found the new end of the table. */
+ break;
+ }
+ else {
+ /* The slot will be past the new end of the table, so free it. */
+ delete ies_slots[slot_end - 1];
+ }
+ }
+ ies_slots.resize(slot_end);
+
+ if (ies_slots.size() > 0) {
+ int packed_size = 0;
+ foreach (IESSlot *slot, ies_slots) {
+ packed_size += slot->ies.packed_size();
+ }
+
+ /* ies_lights starts with an offset table that contains the offset of every slot,
+ * or -1 if the slot is invalid.
+ * Following that table, the packed valid IES lights are stored. */
+ float *data = dscene->ies_lights.alloc(ies_slots.size() + packed_size);
+
+ int offset = ies_slots.size();
+ for (int i = 0; i < ies_slots.size(); i++) {
+ int size = ies_slots[i]->ies.packed_size();
+ if (size > 0) {
+ data[i] = __int_as_float(offset);
+ ies_slots[i]->ies.pack(data + offset);
+ offset += size;
+ }
+ else {
+ data[i] = __int_as_float(-1);
+ }
+ }
+
+ dscene->ies_lights.copy_to_device();
+ }
}
CCL_NAMESPACE_END