Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/scene/light.cpp
| Show First 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | shader_eval.eval( | ||||
| pixels[y * width + x].x = d_output_data[(y * width + x) * num_channels + 0]; | pixels[y * width + x].x = d_output_data[(y * width + x) * num_channels + 0]; | ||||
| pixels[y * width + x].y = d_output_data[(y * width + x) * num_channels + 1]; | pixels[y * width + x].y = d_output_data[(y * width + x) * num_channels + 1]; | ||||
| pixels[y * width + x].z = d_output_data[(y * width + x) * num_channels + 2]; | pixels[y * width + x].z = d_output_data[(y * width + x) * num_channels + 2]; | ||||
| } | } | ||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| static float average_background_energy(Device *device, | |||||
| DeviceScene *dscene, | |||||
| Progress &progress, | |||||
| Scene *scene, | |||||
| Light *light) | |||||
| { | |||||
| if (light->get_light_type() != LIGHT_BACKGROUND) { | |||||
| assert(false); | |||||
| } | |||||
| /* get the resolution from the light's size (we stuff it in there) */ | |||||
| int2 res = make_int2(light->get_map_resolution(), light->get_map_resolution() / 2); | |||||
| /* If it's still unknown, just use the default. */ | |||||
| if (res.x == 0 || res.y == 0) { | |||||
| res = make_int2(1024, 512); | |||||
| VLOG_INFO << "Setting World MIS resolution to default\n"; | |||||
| } | |||||
| vector<float3> pixels; | |||||
| shade_background_pixels(device, dscene, res.x, res.y, pixels, progress); | |||||
| float total_energy = 0.0f; | |||||
| for (int i = 0; i < pixels.size(); i++) { | |||||
| total_energy += scene->shader_manager->linear_rgb_to_gray(pixels[i]); | |||||
| } | |||||
| return total_energy / pixels.size(); | |||||
| } | |||||
| /* Light */ | /* Light */ | ||||
| NODE_DEFINE(Light) | NODE_DEFINE(Light) | ||||
| { | { | ||||
| NodeType *type = NodeType::add("light", create); | NodeType *type = NodeType::add("light", create); | ||||
| static NodeEnum type_enum; | static NodeEnum type_enum; | ||||
| type_enum.insert("point", LIGHT_POINT); | type_enum.insert("point", LIGHT_POINT); | ||||
| ▲ Show 20 Lines • Show All 167 Lines • ▼ Show 20 Lines | foreach (Node *node, geom->get_used_shaders()) { | ||||
| Shader *shader = static_cast<Shader *>(node); | Shader *shader = static_cast<Shader *>(node); | ||||
| if (shader->get_use_mis() && shader->has_surface_emission) { | if (shader->get_use_mis() && shader->has_surface_emission) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| void LightManager::device_update_distribution(Device *, | void LightManager::device_update_distribution(Device *device, | ||||
| DeviceScene *dscene, | DeviceScene *dscene, | ||||
| Scene *scene, | Scene *scene, | ||||
| Progress &progress) | Progress &progress) | ||||
| { | { | ||||
| progress.set_status("Updating Lights", "Computing distribution"); | progress.set_status("Updating Lights", "Computing distribution"); | ||||
| /* count */ | /* count */ | ||||
| size_t num_lights = 0; | size_t num_lights = 0; | ||||
| size_t num_portals = 0; | size_t num_portals = 0; | ||||
| size_t num_background_lights = 0; | size_t num_background_lights = 0; | ||||
| size_t num_distant_lights = 0; | |||||
| size_t num_triangles = 0; | size_t num_triangles = 0; | ||||
| size_t total_triangles = 0; | |||||
| bool background_mis = false; | bool background_mis = false; | ||||
| /* We want to add both lights and emissive triangles to this vector for light tree construction. */ | |||||
| bool light_tree_enabled = scene->integrator->get_use_light_tree(); | |||||
| vector<LightTreePrimitive> light_prims; | |||||
| vector<LightTreePrimitive> distant_lights; | |||||
| vector<uint> object_lookup_offsets(scene->objects.size()); | |||||
| /* When we keep track of the light index, only contributing lights will be added to the device. | |||||
| * Therefore, we want to keep track of the light's index on the device. | |||||
| * However, we also need the light's index in the scene when we're constructing the tree. */ | |||||
| int device_light_index = 0; | |||||
| int scene_light_index = 0; | |||||
| foreach (Light *light, scene->lights) { | foreach (Light *light, scene->lights) { | ||||
| if (light->is_enabled) { | if (light->is_enabled) { | ||||
| if (light_tree_enabled) { | |||||
| LightTreePrimitive light_prim; | |||||
| light_prim.prim_id = ~device_light_index; /* -prim_id - 1 is a light source index. */ | |||||
| light_prim.lamp_id = scene_light_index; | |||||
| /* Distant lights get added to a separate vector. */ | |||||
| if (light->light_type == LIGHT_DISTANT || light->light_type == LIGHT_BACKGROUND) { | |||||
| distant_lights.push_back(light_prim); | |||||
| num_distant_lights++; | |||||
| } | |||||
| else { | |||||
| light_prims.push_back(light_prim); | |||||
| } | |||||
| device_light_index++; | |||||
| } | |||||
| num_lights++; | num_lights++; | ||||
| } | } | ||||
| if (light->is_portal) { | if (light->is_portal) { | ||||
| num_portals++; | num_portals++; | ||||
| } | } | ||||
| scene_light_index++; | |||||
| } | } | ||||
| /* Similarly, we also want to keep track of the index of triangles that are emissive. */ | |||||
| int object_id = 0; | |||||
| foreach (Object *object, scene->objects) { | foreach (Object *object, scene->objects) { | ||||
| if (progress.get_cancel()) | if (progress.get_cancel()) | ||||
| return; | return; | ||||
| if (!object_usable_as_light(object)) { | if (!object_usable_as_light(object)) { | ||||
| object_id++; | |||||
| continue; | continue; | ||||
| } | } | ||||
| /* Count triangles. */ | if (light_tree_enabled) { | ||||
| object_lookup_offsets[object_id] = total_triangles; | |||||
| } | |||||
| /* Count emissive triangles. */ | |||||
| Mesh *mesh = static_cast<Mesh *>(object->get_geometry()); | Mesh *mesh = static_cast<Mesh *>(object->get_geometry()); | ||||
| size_t mesh_num_triangles = mesh->num_triangles(); | size_t mesh_num_triangles = mesh->num_triangles(); | ||||
| for (size_t i = 0; i < mesh_num_triangles; i++) { | for (size_t i = 0; i < mesh_num_triangles; i++) { | ||||
| int shader_index = mesh->get_shader()[i]; | int shader_index = mesh->get_shader()[i]; | ||||
| Shader *shader = (shader_index < mesh->get_used_shaders().size()) ? | Shader *shader = (shader_index < mesh->get_used_shaders().size()) ? | ||||
| static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) : | static_cast<Shader *>(mesh->get_used_shaders()[shader_index]) : | ||||
| scene->default_surface; | scene->default_surface; | ||||
| if (shader->get_use_mis() && shader->has_surface_emission) { | if (shader->get_use_mis() && shader->has_surface_emission) { | ||||
| /* to-do: for the light tree implementation, we eventually want to include emissive | |||||
| * triangles. Right now, point lights are the main concern. */ | |||||
| if (light_tree_enabled) { | |||||
| LightTreePrimitive light_prim; | |||||
| light_prim.prim_id = i; | |||||
| light_prim.object_id = object_id; | |||||
| light_prims.push_back(light_prim); | |||||
| } | |||||
| num_triangles++; | num_triangles++; | ||||
| } | } | ||||
| } | } | ||||
| total_triangles += mesh_num_triangles; | |||||
| object_id++; | |||||
| } | } | ||||
| size_t num_distribution = num_triangles + num_lights; | size_t num_distribution = num_triangles + num_lights; | ||||
| VLOG_INFO << "Total " << num_distribution << " of light distribution primitives."; | VLOG_INFO << "Total " << num_distribution << " of light distribution primitives."; | ||||
| if (light_tree_enabled && num_distribution > 0) { | |||||
| /* For now, we'll start with a smaller number of max lights in a node. | |||||
| * More benchmarking is needed to determine what number works best. */ | |||||
| LightTree light_tree(light_prims, scene, 8); | |||||
| light_prims = light_tree.get_prims(); | |||||
| /* We want to create separate arrays corresponding to triangles and lights, | |||||
| * which will be used to index back into the light tree for PDF calculations. */ | |||||
| uint *light_array = dscene->light_to_tree.alloc(num_lights); | |||||
| uint *object_offsets = dscene->object_lookup_offset.alloc(object_lookup_offsets.size()); | |||||
| uint *triangle_array = dscene->triangle_to_tree.alloc(total_triangles); | |||||
| for (int i = 0; i < object_lookup_offsets.size(); i++) { | |||||
| object_offsets[i] = object_lookup_offsets[i]; | |||||
| } | |||||
| /* First initialize the light tree's nodes. */ | |||||
| const vector<PackedLightTreeNode> &linearized_bvh = light_tree.get_nodes(); | |||||
| KernelLightTreeNode *light_tree_nodes = dscene->light_tree_nodes.alloc(linearized_bvh.size()); | |||||
| KernelLightTreeEmitter *light_tree_emitters = dscene->light_tree_emitters.alloc(light_prims.size()); | |||||
| float max_light_tree_energy = 0.0f; | |||||
| for (int index = 0; index < linearized_bvh.size(); index++) { | |||||
| const PackedLightTreeNode &node = linearized_bvh[index]; | |||||
| light_tree_nodes[index].energy = node.energy; | |||||
| for (int i = 0; i < 3; i++) { | |||||
| light_tree_nodes[index].bounding_box_min[i] = node.bbox.min[i]; | |||||
| light_tree_nodes[index].bounding_box_max[i] = node.bbox.max[i]; | |||||
| light_tree_nodes[index].bounding_cone_axis[i] = node.bcone.axis[i]; | |||||
| } | |||||
| light_tree_nodes[index].theta_o = node.bcone.theta_o; | |||||
| light_tree_nodes[index].theta_e = node.bcone.theta_e; | |||||
| light_tree_nodes[index].bit_trail = node.bit_trail; | |||||
| /* Here we need to make a distinction between interior and leaf nodes. */ | |||||
| if (node.is_leaf_node) { | |||||
| light_tree_nodes[index].num_prims = node.num_lights; | |||||
| light_tree_nodes[index].child_index = -node.first_prim_index; | |||||
| for (int i = 0; i < node.num_lights; i++) { | |||||
| int emitter_index = i + node.first_prim_index; | |||||
| LightTreePrimitive &prim = light_prims[emitter_index]; | |||||
| BoundBox bbox = prim.calculate_bbox(scene); | |||||
| OrientationBounds bcone = prim.calculate_bcone(scene); | |||||
| float energy = prim.calculate_energy(scene); | |||||
| light_tree_emitters[emitter_index].energy = energy; | |||||
| if (energy > max_light_tree_energy) { | |||||
| max_light_tree_energy = energy; | |||||
| } | |||||
| for (int i = 0; i < 3; i++) { | |||||
| light_tree_emitters[emitter_index].bounding_box_min[i] = bbox.min[i]; | |||||
| light_tree_emitters[emitter_index].bounding_box_max[i] = bbox.max[i]; | |||||
| light_tree_emitters[emitter_index].bounding_cone_axis[i] = bcone.axis[i]; | |||||
| } | |||||
| light_tree_emitters[emitter_index].theta_o = bcone.theta_o; | |||||
| light_tree_emitters[emitter_index].theta_e = bcone.theta_e; | |||||
| if (prim.prim_id >= 0) { | |||||
| light_tree_emitters[emitter_index].mesh_light.object_id = prim.object_id; | |||||
| int shader_flag = 0; | |||||
| Object *object = scene->objects[prim.object_id]; | |||||
| Mesh *mesh = static_cast<Mesh *>(object->get_geometry()); | |||||
| if (!(object->get_visibility() & PATH_RAY_CAMERA)) { | |||||
| shader_flag |= SHADER_EXCLUDE_CAMERA; | |||||
| } | |||||
| if (!(object->get_visibility() & PATH_RAY_DIFFUSE)) { | |||||
| shader_flag |= SHADER_EXCLUDE_DIFFUSE; | |||||
| } | |||||
| if (!(object->get_visibility() & PATH_RAY_GLOSSY)) { | |||||
| shader_flag |= SHADER_EXCLUDE_GLOSSY; | |||||
| } | |||||
| if (!(object->get_visibility() & PATH_RAY_TRANSMIT)) { | |||||
| shader_flag |= SHADER_EXCLUDE_TRANSMIT; | |||||
| } | |||||
| if (!(object->get_visibility() & PATH_RAY_VOLUME_SCATTER)) { | |||||
| shader_flag |= SHADER_EXCLUDE_SCATTER; | |||||
| } | |||||
| if (!(object->get_is_shadow_catcher())) { | |||||
| shader_flag |= SHADER_EXCLUDE_SHADOW_CATCHER; | |||||
| } | |||||
| light_tree_emitters[emitter_index].prim_id = prim.prim_id + mesh->prim_offset; | |||||
| light_tree_emitters[emitter_index].mesh_light.shader_flag = shader_flag; | |||||
| triangle_array[prim.prim_id + object_lookup_offsets[prim.object_id]] = emitter_index; | |||||
| } | |||||
| else { | |||||
| Light *lamp = scene->lights[prim.lamp_id]; | |||||
| light_tree_emitters[emitter_index].prim_id = prim.prim_id; | |||||
| light_tree_emitters[emitter_index].lamp.size = lamp->size; | |||||
| light_tree_emitters[emitter_index].lamp.pad = 1.0f; | |||||
| light_array[~prim.prim_id] = emitter_index; | |||||
| } | |||||
| light_tree_emitters[emitter_index].parent_index = index; | |||||
| } | |||||
| } | |||||
| else { | |||||
| light_tree_nodes[index].energy_variance = node.energy_variance; | |||||
| light_tree_nodes[index].child_index = node.second_child_index; | |||||
| } | |||||
| } | |||||
| /* We set the parent node's energy to be the average energy, | |||||
| * which is used for deciding between the tree and distant lights. */ | |||||
| if (max_light_tree_energy > 0.0f) { | |||||
| light_tree_nodes[0].energy = max_light_tree_energy; | |||||
| } | |||||
| /* We also add distant lights to a separate group. */ | |||||
| KernelLightTreeDistantEmitter *light_tree_distant_group = | |||||
| dscene->light_tree_distant_group.alloc(num_distant_lights + 1); | |||||
| /* We use OrientationBounds here to */ | |||||
| OrientationBounds distant_light_bounds = OrientationBounds::empty; | |||||
| float max_distant_light_energy = 0.0f; | |||||
| for (int index = 0; index < num_distant_lights; index++) { | |||||
| LightTreePrimitive prim = distant_lights[index]; | |||||
| Light *light = scene->lights[prim.lamp_id]; | |||||
| OrientationBounds light_bounds; | |||||
| /* Lights in this group are either a background or distant light. */ | |||||
| light_tree_distant_group[index].prim_id = ~prim.prim_id; | |||||
| float energy = 0.0f; | |||||
| if (light->light_type == LIGHT_BACKGROUND) { | |||||
| energy = average_background_energy(device, dscene, progress, scene, light); | |||||
| /* We can set an arbitrary direction for the background light. */ | |||||
| light_bounds.axis[0] = 0.0f; | |||||
| light_bounds.axis[1] = 0.0f; | |||||
| light_bounds.axis[2] = 1.0f; | |||||
| /* to-do: this may depend on portal lights as well. */ | |||||
| light_bounds.theta_o = M_PI_F; | |||||
| } | |||||
| else { | |||||
| energy = prim.calculate_energy(scene); | |||||
| for (int i = 0; i < 3; i++) { | |||||
| light_bounds.axis[i] = -light->dir[i]; | |||||
| } | |||||
| light_bounds.theta_o = tanf(light->angle * 0.5f); | |||||
| } | |||||
| distant_light_bounds = merge(distant_light_bounds, light_bounds); | |||||
| for (int i = 0; i < 3; i++) { | |||||
| light_tree_distant_group[index].direction[i] = light_bounds.axis[i]; | |||||
| } | |||||
| light_tree_distant_group[index].bounding_radius = light_bounds.theta_o; | |||||
| light_tree_distant_group[index].energy = energy; | |||||
| light_array[~prim.prim_id] = index; | |||||
| if (energy > max_distant_light_energy) { | |||||
| max_distant_light_energy = energy; | |||||
| } | |||||
| } | |||||
| /* The net OrientationBounds contain bounding information about all the distant lights. */ | |||||
| light_tree_distant_group[num_distant_lights].prim_id = -1; | |||||
| light_tree_distant_group[num_distant_lights].energy = max_distant_light_energy; | |||||
| for (int i = 0; i < 3; i++) { | |||||
| light_tree_distant_group[num_distant_lights].direction[i] = distant_light_bounds.axis[i]; | |||||
| } | |||||
| light_tree_distant_group[num_distant_lights].bounding_radius = distant_light_bounds.theta_o; | |||||
| dscene->light_tree_nodes.copy_to_device(); | |||||
| dscene->light_tree_emitters.copy_to_device(); | |||||
| dscene->light_tree_distant_group.copy_to_device(); | |||||
| dscene->light_to_tree.copy_to_device(); | |||||
| dscene->object_lookup_offset.copy_to_device(); | |||||
| dscene->triangle_to_tree.copy_to_device(); | |||||
| } | |||||
| /* emission area */ | /* emission area */ | ||||
| KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1); | KernelLightDistribution *distribution = dscene->light_distribution.alloc(num_distribution + 1); | ||||
| float totarea = 0.0f; | float totarea = 0.0f; | ||||
| /* triangles */ | /* triangles */ | ||||
| size_t offset = 0; | size_t offset = 0; | ||||
| int j = 0; | int j = 0; | ||||
| ▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | if (kintegrator->use_direct_light) { | ||||
| /* number of emissives */ | /* number of emissives */ | ||||
| kintegrator->num_distribution = num_distribution; | kintegrator->num_distribution = num_distribution; | ||||
| /* precompute pdfs */ | /* precompute pdfs */ | ||||
| kintegrator->pdf_triangles = 0.0f; | kintegrator->pdf_triangles = 0.0f; | ||||
| kintegrator->pdf_lights = 0.0f; | kintegrator->pdf_lights = 0.0f; | ||||
| /* sample one, with 0.5 probability of light or triangle */ | /* sample one, with 0.5 probability of light or triangle */ | ||||
| /* to-do: this pdf is probably going to need adjustment if a light tree is used. */ | |||||
| kintegrator->num_all_lights = num_lights; | kintegrator->num_all_lights = num_lights; | ||||
| kintegrator->num_distant_lights = num_distant_lights; | |||||
| /* pdf_lights is used when sampling lights, and assumes that | |||||
| * the light has been sampled through the light distribution. | |||||
| * Therefore, we override it for now and adjust the pdf manually in the light tree.*/ | |||||
| if (light_tree_enabled) { | |||||
| kintegrator->pdf_triangles = 1.0f; | |||||
| kintegrator->pdf_lights = 1.0f; | |||||
| } | |||||
| else { | |||||
| if (trianglearea > 0.0f) { | if (trianglearea > 0.0f) { | ||||
| kintegrator->pdf_triangles = 1.0f / trianglearea; | kintegrator->pdf_triangles = 1.0f / trianglearea; | ||||
| if (num_lights) | if (num_lights) | ||||
| kintegrator->pdf_triangles *= 0.5f; | kintegrator->pdf_triangles *= 0.5f; | ||||
| } | } | ||||
| if (num_lights) { | if (num_lights) { | ||||
| kintegrator->pdf_lights = 1.0f / num_lights; | kintegrator->pdf_lights = 1.0f / num_lights; | ||||
| if (trianglearea > 0.0f) | if (trianglearea > 0.0f) | ||||
| kintegrator->pdf_lights *= 0.5f; | kintegrator->pdf_lights *= 0.5f; | ||||
| } | } | ||||
| } | |||||
| kintegrator->use_lamp_mis = use_lamp_mis; | kintegrator->use_lamp_mis = use_lamp_mis; | ||||
| /* bit of an ugly hack to compensate for emitting triangles influencing | /* bit of an ugly hack to compensate for emitting triangles influencing | ||||
| * amount of samples we get for this pass */ | * amount of samples we get for this pass */ | ||||
| kfilm->pass_shadow_scale = 1.0f; | kfilm->pass_shadow_scale = 1.0f; | ||||
| if (kintegrator->pdf_triangles != 0.0f) | if (kintegrator->pdf_triangles != 0.0f) | ||||
| Show All 16 Lines | else { | ||||
| kbackground->portal_offset = 0; | kbackground->portal_offset = 0; | ||||
| kbackground->portal_weight = 0.0f; | kbackground->portal_weight = 0.0f; | ||||
| } | } | ||||
| /* Map */ | /* Map */ | ||||
| kbackground->map_weight = background_mis ? 1.0f : 0.0f; | kbackground->map_weight = background_mis ? 1.0f : 0.0f; | ||||
| } | } | ||||
| else { | else { | ||||
| if (light_tree_enabled) { | |||||
| dscene->light_tree_nodes.free(); | |||||
| dscene->light_tree_emitters.free(); | |||||
| dscene->light_tree_distant_group.free(); | |||||
| dscene->light_to_tree.free(); | |||||
| dscene->object_lookup_offset.free(); | |||||
| dscene->triangle_to_tree.free(); | |||||
| } | |||||
| dscene->light_distribution.free(); | dscene->light_distribution.free(); | ||||
| kintegrator->num_distribution = 0; | kintegrator->num_distribution = 0; | ||||
| kintegrator->num_all_lights = 0; | kintegrator->num_all_lights = 0; | ||||
| kintegrator->pdf_triangles = 0.0f; | kintegrator->pdf_triangles = 0.0f; | ||||
| kintegrator->pdf_lights = 0.0f; | kintegrator->pdf_lights = 0.0f; | ||||
| kintegrator->use_lamp_mis = false; | kintegrator->use_lamp_mis = false; | ||||
| ▲ Show 20 Lines • Show All 493 Lines • ▼ Show 20 Lines | if (progress.get_cancel()) | ||||
| return; | return; | ||||
| update_flags = UPDATE_NONE; | update_flags = UPDATE_NONE; | ||||
| need_update_background = false; | need_update_background = false; | ||||
| } | } | ||||
| void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_background) | void LightManager::device_free(Device *, DeviceScene *dscene, const bool free_background) | ||||
| { | { | ||||
| /* to-do: check if the light tree member variables need to be wrapped in a conditional too*/ | |||||
| dscene->light_tree_nodes.free(); | |||||
| dscene->light_tree_emitters.free(); | |||||
| dscene->light_tree_distant_group.free(); | |||||
| dscene->light_to_tree.free(); | |||||
| dscene->triangle_to_tree.free(); | |||||
| dscene->light_distribution.free(); | dscene->light_distribution.free(); | ||||
| dscene->lights.free(); | dscene->lights.free(); | ||||
| if (free_background) { | if (free_background) { | ||||
| dscene->light_background_marginal_cdf.free(); | dscene->light_background_marginal_cdf.free(); | ||||
| dscene->light_background_conditional_cdf.free(); | dscene->light_background_conditional_cdf.free(); | ||||
| } | } | ||||
| dscene->ies_lights.free(); | dscene->ies_lights.free(); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 132 Lines • Show Last 20 Lines | |||||