Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/scene/light.cpp
| Show First 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | if (strength == zero_float3()) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (is_portal) { | if (is_portal) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| if (light_type == LIGHT_BACKGROUND) { | if (light_type == LIGHT_BACKGROUND) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| return (shader) ? shader->has_surface_emission : scene->default_light->has_surface_emission; | |||||
| const Shader *effective_shader = (shader) ? shader : scene->default_light; | |||||
| return !is_zero(effective_shader->emission_estimate); | |||||
| } | } | ||||
| /* Light Manager */ | /* Light Manager */ | ||||
| LightManager::LightManager() | LightManager::LightManager() | ||||
| { | { | ||||
| update_flags = UPDATE_ALL; | update_flags = UPDATE_ALL; | ||||
| need_update_background = true; | need_update_background = true; | ||||
| ▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | bool LightManager::object_usable_as_light(Object *object) | ||||
| } | } | ||||
| /* Skip if we have no emission shaders. */ | /* Skip if we have no emission shaders. */ | ||||
| /* TODO(sergey): Ideally we want to avoid such duplicated loop, since it'll | /* TODO(sergey): Ideally we want to avoid such duplicated loop, since it'll | ||||
| * iterate all geometry shaders twice (when counting and when calculating | * iterate all geometry shaders twice (when counting and when calculating | ||||
| * triangle area. | * triangle area. | ||||
| */ | */ | ||||
| foreach (Node *node, geom->get_used_shaders()) { | 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->emission_sampling != EMISSION_SAMPLING_NONE) { | ||||
| 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) | ||||
| { | { | ||||
| KernelIntegrator *kintegrator = &dscene->data.integrator; | |||||
| KernelFilm *kfilm = &dscene->data.film; | |||||
| /* Update CDF over lights. */ | |||||
| progress.set_status("Updating Lights", "Computing distribution"); | progress.set_status("Updating Lights", "Computing distribution"); | ||||
| /* count */ | /* Counts emissive triangles in the scene. */ | ||||
| size_t num_lights = 0; | |||||
| size_t num_portals = 0; | |||||
| size_t num_background_lights = 0; | |||||
| size_t num_triangles = 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) { | 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)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Count 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->emission_sampling != EMISSION_SAMPLING_NONE) { | ||||
| num_triangles++; | num_triangles++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| size_t num_distribution = num_triangles + num_lights; | const size_t num_lights = kintegrator->num_lights; | ||||
| const size_t num_background_lights = kintegrator->num_background_lights; | |||||
| const size_t num_distribution = num_triangles + num_lights; | |||||
| /* Distribution size. */ | |||||
| kintegrator->num_distribution = num_distribution; | |||||
| VLOG_INFO << "Total " << num_distribution << " of light distribution primitives."; | VLOG_INFO << "Total " << num_distribution << " of light distribution primitives."; | ||||
| /* 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; | ||||
| 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)) { | ||||
| Show All 28 Lines | foreach (Object *object, scene->objects) { | ||||
| 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->emission_sampling != EMISSION_SAMPLING_NONE) { | ||||
| distribution[offset].totarea = totarea; | distribution[offset].totarea = totarea; | ||||
| distribution[offset].prim = i + mesh->prim_offset; | distribution[offset].prim = i + mesh->prim_offset; | ||||
| distribution[offset].mesh_light.shader_flag = shader_flag; | distribution[offset].mesh_light.shader_flag = shader_flag; | ||||
| distribution[offset].mesh_light.object_id = object_id; | distribution[offset].mesh_light.object_id = object_id; | ||||
| offset++; | offset++; | ||||
| Mesh::Triangle t = mesh->get_triangle(i); | Mesh::Triangle t = mesh->get_triangle(i); | ||||
| if (!t.valid(&mesh->get_verts()[0])) { | if (!t.valid(&mesh->get_verts()[0])) { | ||||
| Show All 11 Lines | for (size_t i = 0; i < mesh_num_triangles; i++) { | ||||
| totarea += triangle_area(p1, p2, p3); | totarea += triangle_area(p1, p2, p3); | ||||
| } | } | ||||
| } | } | ||||
| j++; | j++; | ||||
| } | } | ||||
| float trianglearea = totarea; | const float trianglearea = totarea; | ||||
| /* point lights */ | |||||
| bool use_lamp_mis = false; | /* Lights. */ | ||||
| int light_index = 0; | int light_index = 0; | ||||
| if (num_lights > 0) { | if (num_lights > 0) { | ||||
| float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f; | float lightarea = (totarea > 0.0f) ? totarea / num_lights : 1.0f; | ||||
| foreach (Light *light, scene->lights) { | foreach (Light *light, scene->lights) { | ||||
| if (!light->is_enabled) | if (!light->is_enabled) | ||||
| continue; | continue; | ||||
| distribution[offset].totarea = totarea; | distribution[offset].totarea = totarea; | ||||
| distribution[offset].prim = ~light_index; | distribution[offset].prim = ~light_index; | ||||
| distribution[offset].lamp.pad = 1.0f; | distribution[offset].lamp.pad = 1.0f; | ||||
| distribution[offset].lamp.size = light->size; | distribution[offset].lamp.size = light->size; | ||||
| totarea += lightarea; | totarea += lightarea; | ||||
| if (light->light_type == LIGHT_DISTANT) { | |||||
| use_lamp_mis |= (light->angle > 0.0f && light->use_mis); | |||||
| } | |||||
| else if (light->light_type == LIGHT_POINT || light->light_type == LIGHT_SPOT) { | |||||
| use_lamp_mis |= (light->size > 0.0f && light->use_mis); | |||||
| } | |||||
| else if (light->light_type == LIGHT_AREA) { | |||||
| use_lamp_mis |= light->use_mis; | |||||
| } | |||||
| else if (light->light_type == LIGHT_BACKGROUND) { | |||||
| num_background_lights++; | |||||
| background_mis |= light->use_mis; | |||||
| } | |||||
| light_index++; | light_index++; | ||||
| offset++; | offset++; | ||||
| } | } | ||||
| } | } | ||||
| /* normalize cumulative distribution functions */ | /* normalize cumulative distribution functions */ | ||||
| distribution[num_distribution].totarea = totarea; | distribution[num_distribution].totarea = totarea; | ||||
| distribution[num_distribution].prim = 0.0f; | distribution[num_distribution].prim = 0.0f; | ||||
| distribution[num_distribution].lamp.pad = 0.0f; | distribution[num_distribution].lamp.pad = 0.0f; | ||||
| distribution[num_distribution].lamp.size = 0.0f; | distribution[num_distribution].lamp.size = 0.0f; | ||||
| if (totarea > 0.0f) { | if (totarea > 0.0f) { | ||||
| for (size_t i = 0; i < num_distribution; i++) | for (size_t i = 0; i < num_distribution; i++) | ||||
| distribution[i].totarea /= totarea; | distribution[i].totarea /= totarea; | ||||
| distribution[num_distribution].totarea = 1.0f; | distribution[num_distribution].totarea = 1.0f; | ||||
| } | } | ||||
| if (progress.get_cancel()) | if (progress.get_cancel()) | ||||
| return; | return; | ||||
| /* update device */ | /* Update integrator state. */ | ||||
| KernelIntegrator *kintegrator = &dscene->data.integrator; | |||||
| KernelBackground *kbackground = &dscene->data.background; | |||||
| KernelFilm *kfilm = &dscene->data.film; | |||||
| kintegrator->use_direct_light = (totarea > 0.0f); | kintegrator->use_direct_light = (totarea > 0.0f); | ||||
| if (kintegrator->use_direct_light) { | /* Precompute pdfs for distribution sampling. | ||||
| /* number of emissives */ | * Sample one, with 0.5 probability of light or triangle. */ | ||||
| kintegrator->num_distribution = num_distribution; | kintegrator->distribution_pdf_triangles = 0.0f; | ||||
| kintegrator->distribution_pdf_lights = 0.0f; | |||||
| /* 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) { | if (trianglearea > 0.0f) { | ||||
| kintegrator->pdf_triangles = 1.0f / trianglearea; | kintegrator->distribution_pdf_triangles = 1.0f / trianglearea; | ||||
| if (num_lights) | if (num_lights) { | ||||
| kintegrator->pdf_triangles *= 0.5f; | kintegrator->distribution_pdf_triangles *= 0.5f; | ||||
| } | |||||
| } | } | ||||
| if (num_lights) { | if (num_lights) { | ||||
| kintegrator->pdf_lights = 1.0f / num_lights; | kintegrator->distribution_pdf_lights = 1.0f / num_lights; | ||||
| if (trianglearea > 0.0f) | if (trianglearea > 0.0f) { | ||||
| kintegrator->pdf_lights *= 0.5f; | kintegrator->distribution_pdf_lights *= 0.5f; | ||||
| } | |||||
| } | } | ||||
| 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->distribution_pdf_triangles != 0.0f) { | ||||
| kfilm->pass_shadow_scale /= 0.5f; | 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) { | |||||
| kbackground->portal_offset = light_index; | |||||
| kbackground->num_portals = num_portals; | |||||
| kbackground->portal_weight = 1.0f; | |||||
| } | |||||
| else { | |||||
| kbackground->num_portals = 0; | |||||
| kbackground->portal_offset = 0; | |||||
| kbackground->portal_weight = 0.0f; | |||||
| } | } | ||||
| /* Map */ | if (num_background_lights < num_lights) { | ||||
| kbackground->map_weight = background_mis ? 1.0f : 0.0f; | kfilm->pass_shadow_scale /= (float)(num_lights - num_background_lights) / (float)num_lights; | ||||
| } | } | ||||
| 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; | |||||
| kbackground->num_portals = 0; | |||||
| kbackground->portal_offset = 0; | |||||
| kbackground->portal_weight = 0.0f; | |||||
| kbackground->sun_weight = 0.0f; | |||||
| kbackground->map_weight = 0.0f; | |||||
| kfilm->pass_shadow_scale = 1.0f; | /* Copy distribution to device. */ | ||||
| } | dscene->light_distribution.copy_to_device(); | ||||
| } | } | ||||
| static void background_cdf( | static void background_cdf( | ||||
| int start, int end, int res_x, int res_y, const vector<float3> *pixels, float2 *cond_cdf) | int start, int end, int res_x, int res_y, const vector<float3> *pixels, float2 *cond_cdf) | ||||
| { | { | ||||
| int cdf_width = res_x + 1; | int cdf_width = res_x + 1; | ||||
| /* Conditional CDFs (rows, U direction). */ | /* Conditional CDFs (rows, U direction). */ | ||||
| for (int i = start; i < end; i++) { | for (int i = start; i < end; i++) { | ||||
| Show All 31 Lines | static void background_cdf( | ||||
| } | } | ||||
| } | } | ||||
| void LightManager::device_update_background(Device *device, | void LightManager::device_update_background(Device *device, | ||||
| DeviceScene *dscene, | DeviceScene *dscene, | ||||
| Scene *scene, | Scene *scene, | ||||
| Progress &progress) | Progress &progress) | ||||
| { | { | ||||
| KernelIntegrator *kintegrator = &dscene->data.integrator; | |||||
| KernelBackground *kbackground = &dscene->data.background; | KernelBackground *kbackground = &dscene->data.background; | ||||
| Light *background_light = NULL; | Light *background_light = NULL; | ||||
| bool background_mis = false; | |||||
| /* find background light */ | /* find background light */ | ||||
| foreach (Light *light, scene->lights) { | foreach (Light *light, scene->lights) { | ||||
| if (light->light_type == LIGHT_BACKGROUND) { | if (light->light_type == LIGHT_BACKGROUND && light->is_enabled) { | ||||
| background_light = light; | background_light = light; | ||||
| break; | background_mis |= light->use_mis; | ||||
| } | } | ||||
| } | } | ||||
| kbackground->portal_weight = kintegrator->num_portals > 0 ? 1.0f : 0.0f; | |||||
| kbackground->map_weight = background_mis ? 1.0f : 0.0f; | |||||
| kbackground->sun_weight = 0.0f; | |||||
| /* no background light found, signal renderer to skip sampling */ | /* no background light found, signal renderer to skip sampling */ | ||||
| if (!background_light || !background_light->is_enabled) { | if (!background_light || !background_light->is_enabled) { | ||||
| kbackground->map_res_x = 0; | kbackground->map_res_x = 0; | ||||
| kbackground->map_res_y = 0; | kbackground->map_res_y = 0; | ||||
| kbackground->map_weight = 0.0f; | |||||
| kbackground->sun_weight = 0.0f; | |||||
| kbackground->use_mis = (kbackground->portal_weight > 0.0f); | kbackground->use_mis = (kbackground->portal_weight > 0.0f); | ||||
| return; | return; | ||||
| } | } | ||||
| progress.set_status("Updating Lights", "Importance map"); | progress.set_status("Updating Lights", "Importance map"); | ||||
| assert(dscene->data.integrator.use_direct_light); | |||||
| int2 environment_res = make_int2(0, 0); | int2 environment_res = make_int2(0, 0); | ||||
| Shader *shader = scene->background->get_shader(scene); | Shader *shader = scene->background->get_shader(scene); | ||||
| int num_suns = 0; | int num_suns = 0; | ||||
| foreach (ShaderNode *node, shader->graph->nodes) { | foreach (ShaderNode *node, shader->graph->nodes) { | ||||
| if (node->type == EnvironmentTextureNode::get_node_type()) { | if (node->type == EnvironmentTextureNode::get_node_type()) { | ||||
| EnvironmentTextureNode *env = (EnvironmentTextureNode *)node; | EnvironmentTextureNode *env = (EnvironmentTextureNode *)node; | ||||
| ImageMetaData metadata; | ImageMetaData metadata; | ||||
| if (!env->handle.empty()) { | if (!env->handle.empty()) { | ||||
| Show All 27 Lines | if (node->type == SkyTextureNode::get_node_type()) { | ||||
| Transform sky_transform = transform_inverse(sky->tex_mapping.compute_transform()); | Transform sky_transform = transform_inverse(sky->tex_mapping.compute_transform()); | ||||
| sun_direction = transform_direction(&sky_transform, sun_direction); | sun_direction = transform_direction(&sky_transform, sun_direction); | ||||
| /* Pack sun direction and size. */ | /* Pack sun direction and size. */ | ||||
| float half_angle = sky->get_sun_size() * 0.5f; | float half_angle = sky->get_sun_size() * 0.5f; | ||||
| kbackground->sun = make_float4( | kbackground->sun = make_float4( | ||||
| sun_direction.x, sun_direction.y, sun_direction.z, half_angle); | sun_direction.x, sun_direction.y, sun_direction.z, half_angle); | ||||
| /* empirical value */ | |||||
| kbackground->sun_weight = 4.0f; | kbackground->sun_weight = 4.0f; | ||||
| environment_res.x = max(environment_res.x, 512); | environment_res.x = max(environment_res.x, 512); | ||||
| environment_res.y = max(environment_res.y, 256); | environment_res.y = max(environment_res.y, 256); | ||||
| num_suns++; | num_suns++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | void LightManager::device_update_background(Device *device, | ||||
| VLOG_WORK << "Background MIS build time " << time_dt() - time_start << "\n"; | VLOG_WORK << "Background MIS build time " << time_dt() - time_start << "\n"; | ||||
| /* update device */ | /* update device */ | ||||
| dscene->light_background_marginal_cdf.copy_to_device(); | dscene->light_background_marginal_cdf.copy_to_device(); | ||||
| dscene->light_background_conditional_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_lights(Device *, DeviceScene *dscene, Scene *scene) | ||||
| { | { | ||||
| int num_scene_lights = scene->lights.size(); | /* Counts lights in the scene. */ | ||||
| size_t num_lights = 0; | |||||
| size_t num_portals = 0; | |||||
| size_t num_background_lights = 0; | |||||
| size_t num_distant_lights = 0; | |||||
| bool use_light_mis = false; | |||||
| int num_lights = 0; | |||||
| foreach (Light *light, scene->lights) { | foreach (Light *light, scene->lights) { | ||||
| if (light->is_enabled || light->is_portal) { | if (light->is_enabled) { | ||||
| num_lights++; | num_lights++; | ||||
| if (light->light_type == LIGHT_DISTANT) { | |||||
| num_distant_lights++; | |||||
| } | |||||
| else if (light->light_type == LIGHT_POINT || light->light_type == LIGHT_SPOT) { | |||||
| use_light_mis |= (light->size > 0.0f && light->use_mis); | |||||
| } | |||||
| else if (light->light_type == LIGHT_AREA) { | |||||
| use_light_mis |= light->use_mis; | |||||
| } | |||||
| else if (light->light_type == LIGHT_BACKGROUND) { | |||||
| num_distant_lights++; | |||||
| num_background_lights++; | |||||
| } | |||||
| } | |||||
| if (light->is_portal) { | |||||
| num_portals++; | |||||
| } | } | ||||
| } | } | ||||
| KernelLight *klights = dscene->lights.alloc(num_lights); | /* Update integrator settings. */ | ||||
| KernelIntegrator *kintegrator = &dscene->data.integrator; | |||||
| kintegrator->num_lights = num_lights; | |||||
| kintegrator->num_distant_lights = num_distant_lights; | |||||
| kintegrator->num_background_lights = num_background_lights; | |||||
| kintegrator->use_light_mis = use_light_mis; | |||||
| if (num_lights == 0) { | kintegrator->num_portals = num_portals; | ||||
| VLOG_WORK << "No effective light, ignoring points update."; | kintegrator->portal_offset = num_lights; | ||||
| return; | |||||
| } | /* Create KernelLight for every portal and enabled light in the scene. */ | ||||
| KernelLight *klights = dscene->lights.alloc(num_lights + num_portals); | |||||
| int light_index = 0; | int light_index = 0; | ||||
| int portal_index = num_lights; | |||||
| foreach (Light *light, scene->lights) { | foreach (Light *light, scene->lights) { | ||||
| /* Consider moving portals update to their own function | |||||
| * keeping this one more manageable. */ | |||||
| if (light->is_portal) { | |||||
| assert(light->light_type == LIGHT_AREA); | |||||
| float3 extentu = light->axisu * (light->sizeu * light->size); | |||||
| float3 extentv = light->axisv * (light->sizev * light->size); | |||||
| float area = len(extentu) * len(extentv); | |||||
| 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[portal_index].co = light->co; | |||||
| klights[portal_index].area.extentu = extentu; | |||||
| klights[portal_index].area.extentv = extentv; | |||||
| klights[portal_index].area.invarea = invarea; | |||||
| klights[portal_index].area.dir = dir; | |||||
| klights[portal_index].tfm = light->tfm; | |||||
| klights[portal_index].itfm = transform_inverse(light->tfm); | |||||
| portal_index++; | |||||
| continue; | |||||
| } | |||||
| if (!light->is_enabled) { | if (!light->is_enabled) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| float3 co = light->co; | float3 co = light->co; | ||||
| Shader *shader = (light->shader) ? light->shader : scene->default_light; | Shader *shader = (light->shader) ? light->shader : scene->default_light; | ||||
| int shader_id = scene->shader_manager->get_shader_id(shader); | int shader_id = scene->shader_manager->get_shader_id(shader); | ||||
| int max_bounces = light->max_bounces; | int max_bounces = light->max_bounces; | ||||
| Show All 30 Lines | if (light->light_type == LIGHT_POINT) { | ||||
| shader_id &= ~SHADER_AREA_LIGHT; | shader_id &= ~SHADER_AREA_LIGHT; | ||||
| float radius = light->size; | float radius = light->size; | ||||
| float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f; | float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f; | ||||
| if (light->use_mis && radius > 0.0f) | if (light->use_mis && radius > 0.0f) | ||||
| shader_id |= SHADER_USE_MIS; | shader_id |= SHADER_USE_MIS; | ||||
| klights[light_index].co[0] = co.x; | klights[light_index].co = co; | ||||
| klights[light_index].co[1] = co.y; | |||||
| klights[light_index].co[2] = co.z; | |||||
| klights[light_index].spot.radius = radius; | klights[light_index].spot.radius = radius; | ||||
| klights[light_index].spot.invarea = invarea; | klights[light_index].spot.invarea = invarea; | ||||
| } | } | ||||
| else if (light->light_type == LIGHT_DISTANT) { | else if (light->light_type == LIGHT_DISTANT) { | ||||
| shader_id &= ~SHADER_AREA_LIGHT; | shader_id &= ~SHADER_AREA_LIGHT; | ||||
| float angle = light->angle / 2.0f; | float angle = light->angle / 2.0f; | ||||
| float radius = tanf(angle); | float radius = tanf(angle); | ||||
| float cosangle = cosf(angle); | float cosangle = cosf(angle); | ||||
| float area = M_PI_F * radius * radius; | float area = M_PI_F * radius * radius; | ||||
| float invarea = (area > 0.0f) ? 1.0f / area : 1.0f; | float invarea = (area > 0.0f) ? 1.0f / area : 1.0f; | ||||
| float3 dir = light->dir; | float3 dir = light->dir; | ||||
| dir = safe_normalize(dir); | dir = safe_normalize(dir); | ||||
| if (light->use_mis && area > 0.0f) | if (light->use_mis && area > 0.0f) | ||||
| shader_id |= SHADER_USE_MIS; | shader_id |= SHADER_USE_MIS; | ||||
| klights[light_index].co[0] = dir.x; | klights[light_index].co = dir; | ||||
| klights[light_index].co[1] = dir.y; | |||||
| klights[light_index].co[2] = dir.z; | |||||
| klights[light_index].distant.invarea = invarea; | klights[light_index].distant.invarea = invarea; | ||||
| klights[light_index].distant.radius = radius; | klights[light_index].distant.radius = radius; | ||||
| klights[light_index].distant.cosangle = cosangle; | klights[light_index].distant.cosangle = cosangle; | ||||
| } | } | ||||
| else if (light->light_type == LIGHT_BACKGROUND) { | else if (light->light_type == LIGHT_BACKGROUND) { | ||||
| uint visibility = scene->background->get_visibility(); | uint visibility = scene->background->get_visibility(); | ||||
| dscene->data.background.light_index = light_index; | |||||
| shader_id &= ~SHADER_AREA_LIGHT; | shader_id &= ~SHADER_AREA_LIGHT; | ||||
| shader_id |= SHADER_USE_MIS; | shader_id |= SHADER_USE_MIS; | ||||
| if (!(visibility & PATH_RAY_DIFFUSE)) { | if (!(visibility & PATH_RAY_DIFFUSE)) { | ||||
| shader_id |= SHADER_EXCLUDE_DIFFUSE; | shader_id |= SHADER_EXCLUDE_DIFFUSE; | ||||
| } | } | ||||
| if (!(visibility & PATH_RAY_GLOSSY)) { | if (!(visibility & PATH_RAY_GLOSSY)) { | ||||
| shader_id |= SHADER_EXCLUDE_GLOSSY; | shader_id |= SHADER_EXCLUDE_GLOSSY; | ||||
| } | } | ||||
| if (!(visibility & PATH_RAY_TRANSMIT)) { | if (!(visibility & PATH_RAY_TRANSMIT)) { | ||||
| shader_id |= SHADER_EXCLUDE_TRANSMIT; | shader_id |= SHADER_EXCLUDE_TRANSMIT; | ||||
| } | } | ||||
| if (!(visibility & PATH_RAY_VOLUME_SCATTER)) { | if (!(visibility & PATH_RAY_VOLUME_SCATTER)) { | ||||
| shader_id |= SHADER_EXCLUDE_SCATTER; | shader_id |= SHADER_EXCLUDE_SCATTER; | ||||
| } | } | ||||
| } | } | ||||
| else if (light->light_type == LIGHT_AREA) { | else if (light->light_type == LIGHT_AREA) { | ||||
| float3 axisu = light->axisu * (light->sizeu * light->size); | float3 extentu = light->axisu * (light->sizeu * light->size); | ||||
| float3 axisv = light->axisv * (light->sizev * light->size); | float3 extentv = light->axisv * (light->sizev * light->size); | ||||
| float area = len(axisu) * len(axisv); | float area = len(extentu) * len(extentv); | ||||
| if (light->round) { | if (light->round) { | ||||
| area *= -M_PI_4_F; | area *= -M_PI_4_F; | ||||
| } | } | ||||
| float invarea = (area != 0.0f) ? 1.0f / area : 1.0f; | float invarea = (area != 0.0f) ? 1.0f / area : 1.0f; | ||||
| float3 dir = light->dir; | float3 dir = light->dir; | ||||
| /* Convert from spread angle 0..180 to 90..0, clamping to a minimum | /* Convert from spread angle 0..180 to 90..0, clamping to a minimum | ||||
| * angle to avoid excessive noise. */ | * angle to avoid excessive noise. */ | ||||
| const float min_spread_angle = 1.0f * M_PI_F / 180.0f; | const float min_spread_angle = 1.0f * M_PI_F / 180.0f; | ||||
| const float spread_angle = 0.5f * (M_PI_F - max(light->spread, min_spread_angle)); | const float spread_angle = 0.5f * (M_PI_F - max(light->spread, min_spread_angle)); | ||||
| /* Normalization computed using: | /* Normalization computed using: | ||||
| * integrate cos(x) * (1 - tan(x) * tan(a)) * sin(x) from x = 0 to pi/2 - a. */ | * integrate cos(x) * (1 - tan(x) * tan(a)) * sin(x) from x = 0 to pi/2 - a. */ | ||||
| const float tan_spread = tanf(spread_angle); | const float tan_spread = tanf(spread_angle); | ||||
| const float normalize_spread = 2.0f / (2.0f + (2.0f * spread_angle - M_PI_F) * tan_spread); | const float normalize_spread = 2.0f / (2.0f + (2.0f * spread_angle - M_PI_F) * tan_spread); | ||||
| dir = safe_normalize(dir); | dir = safe_normalize(dir); | ||||
| if (light->use_mis && area != 0.0f) | if (light->use_mis && area != 0.0f) | ||||
| shader_id |= SHADER_USE_MIS; | shader_id |= SHADER_USE_MIS; | ||||
| klights[light_index].co[0] = co.x; | klights[light_index].co = co; | ||||
| klights[light_index].co[1] = co.y; | klights[light_index].area.extentu = extentu; | ||||
| klights[light_index].co[2] = co.z; | klights[light_index].area.extentv = extentv; | ||||
| 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.invarea = invarea; | ||||
| klights[light_index].area.dir[0] = dir.x; | klights[light_index].area.dir = dir; | ||||
| klights[light_index].area.dir[1] = dir.y; | |||||
| klights[light_index].area.dir[2] = dir.z; | |||||
| klights[light_index].area.tan_spread = tan_spread; | klights[light_index].area.tan_spread = tan_spread; | ||||
| klights[light_index].area.normalize_spread = normalize_spread; | klights[light_index].area.normalize_spread = normalize_spread; | ||||
| } | } | ||||
| else if (light->light_type == LIGHT_SPOT) { | else if (light->light_type == LIGHT_SPOT) { | ||||
| shader_id &= ~SHADER_AREA_LIGHT; | shader_id &= ~SHADER_AREA_LIGHT; | ||||
| float radius = light->size; | float radius = light->size; | ||||
| float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f; | float invarea = (radius > 0.0f) ? 1.0f / (M_PI_F * radius * radius) : 1.0f; | ||||
| float spot_angle = cosf(light->spot_angle * 0.5f); | float cos_half_spot_angle = cosf(light->spot_angle * 0.5f); | ||||
| float spot_smooth = (1.0f - spot_angle) * light->spot_smooth; | float spot_smooth = (1.0f - cos_half_spot_angle) * light->spot_smooth; | ||||
| float3 dir = light->dir; | float3 dir = light->dir; | ||||
| dir = safe_normalize(dir); | dir = safe_normalize(dir); | ||||
| if (light->use_mis && radius > 0.0f) | if (light->use_mis && radius > 0.0f) | ||||
| shader_id |= SHADER_USE_MIS; | shader_id |= SHADER_USE_MIS; | ||||
| klights[light_index].co[0] = co.x; | klights[light_index].co = co; | ||||
| klights[light_index].co[1] = co.y; | |||||
| klights[light_index].co[2] = co.z; | |||||
| klights[light_index].spot.radius = radius; | klights[light_index].spot.radius = radius; | ||||
| klights[light_index].spot.invarea = invarea; | klights[light_index].spot.invarea = invarea; | ||||
| klights[light_index].spot.spot_angle = spot_angle; | klights[light_index].spot.cos_half_spot_angle = cos_half_spot_angle; | ||||
| klights[light_index].spot.spot_smooth = spot_smooth; | klights[light_index].spot.spot_smooth = spot_smooth; | ||||
| klights[light_index].spot.dir[0] = dir.x; | klights[light_index].spot.dir = dir; | ||||
| 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].shader_id = shader_id; | ||||
| klights[light_index].max_bounces = max_bounces; | klights[light_index].max_bounces = max_bounces; | ||||
| klights[light_index].random = random; | klights[light_index].random = random; | ||||
| klights[light_index].use_caustics = light->use_caustics; | klights[light_index].use_caustics = light->use_caustics; | ||||
| klights[light_index].tfm = light->tfm; | klights[light_index].tfm = light->tfm; | ||||
| klights[light_index].itfm = transform_inverse(light->tfm); | klights[light_index].itfm = transform_inverse(light->tfm); | ||||
| auto it = scene->lightgroups.find(light->lightgroup); | auto it = scene->lightgroups.find(light->lightgroup); | ||||
| if (it != scene->lightgroups.end()) { | if (it != scene->lightgroups.end()) { | ||||
| klights[light_index].lightgroup = it->second; | klights[light_index].lightgroup = it->second; | ||||
| } | } | ||||
| else { | else { | ||||
| klights[light_index].lightgroup = LIGHTGROUP_NONE; | klights[light_index].lightgroup = LIGHTGROUP_NONE; | ||||
| } | } | ||||
| light_index++; | light_index++; | ||||
| } | } | ||||
| /* TODO(sergey): Consider moving portals update to their own function | VLOG_INFO << "Number of lights sent to the device: " << num_lights; | ||||
| * keeping this one more manageable. | |||||
| */ | |||||
| foreach (Light *light, scene->lights) { | |||||
| if (!light->is_portal) | |||||
| continue; | |||||
| assert(light->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_INFO << "Number of lights sent to the device: " << light_index; | |||||
| VLOG_INFO << "Number of lights without contribution: " << num_scene_lights - light_index; | |||||
| dscene->lights.copy_to_device(); | dscene->lights.copy_to_device(); | ||||
| } | } | ||||
| void LightManager::device_update(Device *device, | void LightManager::device_update(Device *device, | ||||
| DeviceScene *dscene, | DeviceScene *dscene, | ||||
| Scene *scene, | Scene *scene, | ||||
| Progress &progress) | Progress &progress) | ||||
| Show All 9 Lines | void LightManager::device_update(Device *device, | ||||
| VLOG_INFO << "Total " << scene->lights.size() << " lights."; | VLOG_INFO << "Total " << scene->lights.size() << " lights."; | ||||
| /* Detect which lights are enabled, also determines if we need to update the background. */ | /* Detect which lights are enabled, also determines if we need to update the background. */ | ||||
| test_enabled_lights(scene); | test_enabled_lights(scene); | ||||
| device_free(device, dscene, need_update_background); | device_free(device, dscene, need_update_background); | ||||
| device_update_points(device, dscene, scene); | device_update_lights(device, dscene, scene); | ||||
| if (progress.get_cancel()) | |||||
| return; | |||||
| device_update_distribution(device, dscene, scene, progress); | |||||
| if (progress.get_cancel()) | if (progress.get_cancel()) | ||||
| return; | return; | ||||
| if (need_update_background) { | if (need_update_background) { | ||||
| device_update_background(device, dscene, scene, progress); | device_update_background(device, dscene, scene, progress); | ||||
| if (progress.get_cancel()) | if (progress.get_cancel()) | ||||
| return; | return; | ||||
| } | } | ||||
| device_update_distribution(device, dscene, scene, progress); | |||||
| if (progress.get_cancel()) | |||||
| return; | |||||
| device_update_ies(dscene); | device_update_ies(dscene); | ||||
| if (progress.get_cancel()) | if (progress.get_cancel()) | ||||
| return; | return; | ||||
| update_flags = UPDATE_NONE; | update_flags = UPDATE_NONE; | ||||
| need_update_background = false; | need_update_background = false; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 142 Lines • Show Last 20 Lines | |||||