Commit: 7b3c1a203efdecf08d0aa041a76a984f2d72d870 Author: Jeffrey Liu Date: Sat Jul 9 16:01:03 2022 -0400 Branches: soc-2022-many-lights-sampling https://developer.blender.org/rB7b3c1a203efdecf08d0aa041a76a984f2d72d870
Cycles: update distant light importance heuristics =================================================================== M intern/cycles/kernel/light/light_tree.h M intern/cycles/kernel/types.h M intern/cycles/scene/light.cpp =================================================================== diff --git a/intern/cycles/kernel/light/light_tree.h b/intern/cycles/kernel/light/light_tree.h index 1b9e5d3806b..0ba28982e91 100644 --- a/intern/cycles/kernel/light/light_tree.h +++ b/intern/cycles/kernel/light/light_tree.h @@ -69,7 +69,7 @@ ccl_device float light_tree_node_importance(const float3 P, } /* to-do: find a good approximation for this value. */ - const float f_a = 1; + const float f_a = 1.0f; float importance = f_a * cos_theta_i_prime * energy / distance_squared * cos_theta_prime; return importance; @@ -225,8 +225,6 @@ ccl_device int light_tree_sample(KernelGlobals kg, return -1; } -/* to-do: assign relative importances for the background and distant lights. - * Can we somehow adjust the importance measure to account for these as well? */ ccl_device float light_tree_distant_light_importance(KernelGlobals kg, const float3 P, const float3 N, @@ -234,7 +232,28 @@ ccl_device float light_tree_distant_light_importance(KernelGlobals kg, { ccl_global const KernelLightTreeDistantEmitter *kdistant = &kernel_data_fetch( light_tree_distant_group, index); - return kdistant->energy; + + if (kdistant->energy == 0.0f) { + return 0.0f; + } + + const float3 light_axis = make_float3( + kdistant->direction[0], kdistant->direction[1], kdistant->direction[2]); + const float theta = fast_acosf(dot(N, light_axis)); + const float theta_i_prime = theta - kdistant->bounding_radius; + + float cos_theta_i_prime = 1; + if (theta_i_prime > M_PI_2_F) { + return 0.0f; + } else if (theta - kdistant->bounding_radius > 0) { + cos_theta_i_prime = fast_cosf(theta - kdistant->bounding_radius); + } + + /* to-do: find a good value for this. */ + const float f_a = 1.0f; + float importance = f_a * cos_theta_i_prime * kdistant->energy; + + return importance; } template<bool in_volume_segment> @@ -286,7 +305,16 @@ ccl_device int light_tree_sample_distant_lights(KernelGlobals kg, /* We need to be able to find the probability of selecting a given light, for MIS. */ ccl_device float light_tree_pdf(KernelGlobals kg, const float3 P, const float3 N, const int prim) { - float pdf = kernel_data.integrator.pdf_light_tree; + float distant_light_importance = light_tree_distant_light_importance( + kg, P, N, kernel_data.integrator.num_distant_lights); + float light_tree_importance = 0.0f; + if (kernel_data.integrator.num_distribution > kernel_data.integrator.num_distant_lights) { + const ccl_global KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, 0); + light_tree_importance = light_tree_cluster_importance(kg, P, N, kroot); + } + const float total_group_importance = light_tree_importance + distant_light_importance; + assert(total_group_importance != 0.0f); + float pdf = light_tree_importance / total_group_importance; const int emitter = (prim >= 0) ? kernel_data_fetch(triangle_to_tree, prim) : kernel_data_fetch(light_to_tree, ~prim); @@ -351,7 +379,16 @@ ccl_device float distant_lights_pdf(KernelGlobals kg, const float3 N, const int prim) { - float pdf = (1 - kernel_data.integrator.pdf_light_tree); + float distant_light_importance = light_tree_distant_light_importance( + kg, P, N, kernel_data.integrator.num_distant_lights); + float light_tree_importance = 0.0f; + if (kernel_data.integrator.num_distribution > kernel_data.integrator.num_distant_lights) { + const ccl_global KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, 0); + light_tree_importance = light_tree_cluster_importance(kg, P, N, kroot); + } + const float total_group_importance = light_tree_importance + distant_light_importance; + assert(total_group_importance != 0.0f); + float pdf = distant_light_importance / total_group_importance; /* The light_to_tree array doubles as a lookup table for * both the light tree as well as the distant lights group.*/ @@ -383,16 +420,31 @@ ccl_device bool light_tree_sample_from_position(KernelGlobals kg, const uint32_t path_flag, ccl_private LightSample *ls) { + float distant_light_importance = light_tree_distant_light_importance( + kg, P, N, kernel_data.integrator.num_distant_lights); + float light_tree_importance = 0.0f; + if (kernel_data.integrator.num_distribution > kernel_data.integrator.num_distant_lights) { + const ccl_global KernelLightTreeNode *kroot = &kernel_data_fetch(light_tree_nodes, 0); + light_tree_importance = light_tree_cluster_importance(kg, P, N, kroot); + } + const float total_importance = light_tree_importance + distant_light_importance; + + if (total_importance == 0.0f) { + return false; + } + + const float light_tree_probability = light_tree_importance / total_importance; + float pdf_factor = 1.0f; bool ret; float tree_u = path_state_rng_1D(kg, rng_state, 1); - if (tree_u < kernel_data.integrator.pdf_light_tree) { - pdf_factor *= kernel_data.integrator.pdf_light_tree; + if (tree_u < light_tree_probability) { + pdf_factor *= light_tree_probability; ret = light_tree_sample<false>( kg, rng_state, randu, randv, time, N, P, bounce, path_flag, ls, &pdf_factor); } else { - pdf_factor *= (1 - kernel_data.integrator.pdf_light_tree); + pdf_factor *= (1 - light_tree_probability); ret = light_tree_sample_distant_lights<false>( kg, rng_state, randu, randv, time, N, P, bounce, path_flag, ls, &pdf_factor); } diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 9def2e5690b..793b6d4c309 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -1303,12 +1303,11 @@ typedef struct KernelIntegrator { int direct_light_sampling_type; /* Light tree. */ - float pdf_light_tree; int use_light_tree; float splitting_threshold; /* padding */ - int pad1; + int pad1, pad2; } KernelIntegrator; static_assert_align(KernelIntegrator, 16); diff --git a/intern/cycles/scene/light.cpp b/intern/cycles/scene/light.cpp index 6278e3efd93..15cbfc36d7a 100644 --- a/intern/cycles/scene/light.cpp +++ b/intern/cycles/scene/light.cpp @@ -389,7 +389,6 @@ void LightManager::device_update_distribution(Device *device, size_t num_distribution = num_triangles + num_lights; VLOG_INFO << "Total " << num_distribution << " of light distribution primitives."; - float pdf_light_tree = 0.0f; 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. */ @@ -492,11 +491,15 @@ void LightManager::device_update_distribution(Device *device, /* We also add distant lights to a separate group. */ KernelLightTreeDistantEmitter *light_tree_distant_group = - dscene->light_tree_distant_group.alloc(num_distant_lights); + dscene->light_tree_distant_group.alloc(num_distant_lights + 1); + + /* We use OrientationBounds here to */ + OrientationBounds distant_light_bounds = OrientationBounds::empty; float 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; @@ -506,30 +509,39 @@ void LightManager::device_update_distribution(Device *device, energy = average_background_energy(device, dscene, progress, scene, light); /* We can set an arbitrary direction for the background light. */ - light_tree_distant_group[index].direction[0] = 0.0f; - light_tree_distant_group[index].direction[1] = 0.0f; - light_tree_distant_group[index].direction[2] = 1.0f; + 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_tree_distant_group[index].bounding_radius = M_PI_F; + light_bounds.theta_o = M_PI_F; } else { energy = prim.calculate_energy(scene); - for (int i = 0; i < 3; i++) { - light_tree_distant_group[index].direction[i] = -light->co[i]; + light_bounds.axis[i] = -light->dir[i]; } - light_tree_distant_group[index].bounding_radius = tanf(light->angle * 0.5f); + 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; distant_light_energy += energy; - } + } - if (light_tree_energy > 0.0f) { - pdf_light_tree = light_tree_energy / (light_tree_energy + distant_light_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 = 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(); @@ -688,7 +700,6 @@ void LightManager::device_update_distribution(Device *device, /* 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 a @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs