[Bf-blender-cvs] [118731d7d41] gsoc-2018-many-light-sampling: Cycles: New design for PDF computations
Erik Englesson
noreply at git.blender.org
Fri Jun 22 08:54:56 CEST 2018
Commit: 118731d7d415eade1584cdd005a8101e5a438a65
Author: Erik Englesson
Date: Thu Jun 14 17:51:46 2018 +0200
Branches: gsoc-2018-many-light-sampling
https://developer.blender.org/rB118731d7d415eade1584cdd005a8101e5a438a65
Cycles: New design for PDF computations
Now there are functions to calculate the picking
probability for a given lamp/triangle. Fixed
a bug that lamps was before triangles in the
distribution array.
===================================================================
M intern/cycles/kernel/kernel_emission.h
M intern/cycles/kernel/kernel_light.h
M intern/cycles/kernel/kernel_path_surface.h
M intern/cycles/kernel/kernel_textures.h
M intern/cycles/kernel/kernel_types.h
M intern/cycles/render/light.cpp
M intern/cycles/render/light_tree.cpp
M intern/cycles/render/scene.cpp
M intern/cycles/render/scene.h
===================================================================
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index a5556c3be8f..a4d43a88166 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -212,6 +212,7 @@ ccl_device_noinline float3 indirect_primitive_emission(KernelGlobals *kg, Shader
/* multiple importance sampling, get triangle light pdf,
* and compute weight with respect to BSDF pdf */
float pdf = triangle_light_pdf(kg, sd, t);
+ pdf *= light_distribution_pdf(kg, sd->P, sd->prim);
float mis_weight = power_heuristic(bsdf_pdf, pdf);
return L*mis_weight;
@@ -273,6 +274,9 @@ ccl_device_noinline bool indirect_lamp_emission(KernelGlobals *kg,
if(!(state->flag & PATH_RAY_MIS_SKIP)) {
/* multiple importance sampling, get regular light pdf,
* and compute weight with respect to BSDF pdf */
+
+ /* multiply with light picking probablity to pdf */
+ ls.pdf *= light_distribution_pdf(kg, ls.P, ~ls.lamp);
float mis_weight = power_heuristic(state->ray_pdf, ls.pdf);
L *= mis_weight;
}
@@ -324,6 +328,7 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg,
if(!(state->flag & PATH_RAY_MIS_SKIP) && res) {
/* multiple importance sampling, get background light pdf for ray
* direction, and compute weight with respect to BSDF pdf */
+ /* TODO: PDF should be multiplied by picking probability */
float pdf = background_light_pdf(kg, ray->P, ray->D);
float mis_weight = power_heuristic(state->ray_pdf, pdf);
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index b77f9074717..392690b6823 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -440,7 +440,7 @@ ccl_device float background_light_pdf(KernelGlobals *kg, float3 P, float3 direct
/* Portal sampling is not possible here because all portals point to the wrong side.
* If map sampling is possible, it would be used instead, otherwise fallback sampling is used. */
if(portal_sampling_pdf == 1.0f) {
- return kernel_data.integrator.pdf_lights / M_4PI_F;
+ return 1.0f / M_4PI_F;
}
else {
/* Force map sampling. */
@@ -452,7 +452,7 @@ ccl_device float background_light_pdf(KernelGlobals *kg, float3 P, float3 direct
/* Evaluate PDF of sampling this direction by map sampling. */
map_pdf = background_map_pdf(kg, direction) * (1.0f - portal_sampling_pdf);
}
- return (portal_pdf + map_pdf) * kernel_data.integrator.pdf_lights;
+ return portal_pdf + map_pdf;
}
#endif
@@ -624,8 +624,6 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg,
}
}
- ls->pdf *= kernel_data.integrator.pdf_lights;
-
return (ls->pdf > 0.0f);
}
@@ -768,8 +766,6 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D,
return false;
}
- ls->pdf *= kernel_data.integrator.pdf_lights;
-
return true;
}
@@ -808,13 +804,12 @@ ccl_device_inline bool triangle_world_space_vertices(KernelGlobals *kg, int obje
ccl_device_inline float triangle_light_pdf_area(KernelGlobals *kg, const float3 Ng, const float3 I, float t)
{
- float pdf = kernel_data.integrator.pdf_triangles;
float cos_pi = fabsf(dot(Ng, I));
if(cos_pi == 0.0f)
return 0.0f;
- return t*t*pdf/cos_pi;
+ return t*t/cos_pi;
}
ccl_device_forceinline float triangle_light_pdf(KernelGlobals *kg, ShaderData *sd, float t)
@@ -882,6 +877,7 @@ ccl_device_forceinline float triangle_light_pdf(KernelGlobals *kg, ShaderData *s
const float area_pre = triangle_area(V[0], V[1], V[2]);
pdf = pdf * area_pre / area;
}
+
return pdf;
}
}
@@ -894,7 +890,7 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals *kg, int prim, i
* to the length of the edges of the triangle. */
float3 V[3];
- bool has_motion = triangle_world_space_vertices(kg, object, prim, time, V);
+ triangle_world_space_vertices(kg, object, prim, time, V);
const float3 e0 = V[1] - V[0];
const float3 e1 = V[2] - V[0];
@@ -903,7 +899,6 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals *kg, int prim, i
const float3 N0 = cross(e0, e1);
float Nl = 0.0f;
ls->Ng = safe_normalize_len(N0, &Nl);
- float area = 0.5f * Nl;
/* flip normal if necessary */
const int object_flag = kernel_tex_fetch(__object_flag, object);
@@ -1000,13 +995,7 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals *kg, int prim, i
return;
}
else {
- if(has_motion) {
- /* get the center frame vertices, this is what the PDF was calculated from */
- triangle_world_space_vertices(kg, object, prim, -1.0f, V);
- area = triangle_area(V[0], V[1], V[2]);
- }
- const float pdf = area * kernel_data.integrator.pdf_triangles;
- ls->pdf = pdf / solid_angle;
+ ls->pdf = 1.0f / solid_angle;
}
}
else {
@@ -1020,14 +1009,7 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals *kg, int prim, i
/* compute incoming direction, distance and pdf */
ls->D = normalize_len(ls->P - P, &ls->t);
ls->pdf = triangle_light_pdf_area(kg, ls->Ng, -ls->D, ls->t);
- if(has_motion && area != 0.0f) {
- /* scale the PDF.
- * area = the area the sample was taken from
- * area_pre = the are from which pdf_triangles was calculated from */
- triangle_world_space_vertices(kg, object, prim, -1.0f, V);
- const float area_pre = triangle_area(V[0], V[1], V[2]);
- ls->pdf = ls->pdf * area_pre / area;
- }
+
ls->u = u;
ls->v = v;
}
@@ -1111,7 +1093,9 @@ ccl_device void update_parent_node(KernelGlobals *kg, int node_offset,
(*nemitters) = __float_as_int(node[3]);
}
-ccl_device int sample_light_bvh(KernelGlobals *kg, float3 P, float randu, float *pdf_factor)
+/* picks a light from the light BVH and returns its index and the probability of
+ * picking this light. */
+ccl_device int light_bvh_sample(KernelGlobals *kg, float3 P, float randu, float *pdf_factor)
{
int index = -1;
*pdf_factor = 1.0f;
@@ -1164,6 +1148,124 @@ ccl_device int sample_light_bvh(KernelGlobals *kg, float3 P, float randu, float
return index;
}
+/* converts from an emissive triangle index to the corresponding
+ * light distribution index. */
+ccl_device int triangle_to_distribution(KernelGlobals *kg, int triangle_id)
+{
+ /* binary search to find triangle_id which then gives distribution_id */
+ /* equivalent to implementation of std::lower_bound */
+ /* todo: of complexity log(N) now. could be made constant with a hash table? */
+ int first = 0;
+ int last = kernel_data.integrator.num_triangle_lights;
+ int count = last - first;
+ int middle,step;
+ while (count > 0) {
+ step = count / 2;
+ middle = first + step;
+ int triangle = kernel_tex_fetch(__triangle_to_distribution, middle*2);
+ if (triangle < triangle_id) {
+ first = middle + 1;
+ count -= step + 1;
+ }
+ else
+ count = step;
+ }
+
+ int triangle = kernel_tex_fetch(__triangle_to_distribution, first*2);
+ kernel_assert(triangle == triangle_id);
+
+ return kernel_tex_fetch(__triangle_to_distribution, first*2+1);
+}
+
+/* computes the probability of picking a light in the given node_id */
+ccl_device float light_bvh_pdf(KernelGlobals *kg, float3 P, int node_id){
+ float pdf = 1.0f;
+ /* read in first part of root node of light BVH */
+ int secondChildOffset, distribution_id, nemitters;
+ update_parent_node(kg, 0, &secondChildOffset, &distribution_id, &nemitters);
+
+ int offset = 0;
+ do{
+
+ if(nemitters > 0){ // Found our leaf node
+ kernel_assert(offset == node_id);
+ if(nemitters > 1){
+ pdf *= 1.0f / (float)nemitters;
+ }
+ break;
+ } else { // Interior node, pick left or right depending on node_id
+
+ /* calculate probability of going down left node */
+ int child_offsetL = offset + 4;
+ int child_offsetR = 4*secondChildOffset;
+ float I_L = calc_node_importance(kg, P, child_offsetL);
+ float I_R = calc_node_importance(kg, P, child_offsetR);
+ float P_L = I_L / ( I_L + I_R);
+
+ /* choose which child to go down to. assumes nodes have been flattened
+ * in a depth first manner. */
+ if(node_id < child_offsetR){
+ offset = child_offsetL;
+ pdf *= P_L;
+ } else {
+ offset = child_offsetR;
+ pdf *= 1.0f - P_L;
+ }
+
+ /* update parent node info for next iteration */
+ update_parent_node(kg, offset, &secondChildOffset,
+ &distribution_id, &nemitters);
+ }
+
+ } while(true);
+
+ return pdf;
+}
+
+/* computes the the probability of picking the given light out of all lights */
+ccl_device float light_distribution_pdf(KernelGlobals *kg, float3 P, int prim_id)
+{
+ /* convert from triangle/lamp to light distribution */
+ int distribution_id;
+ if(prim_id >= 0){ // Triangle_id = prim_id
+ distribution_id = triangle_to_distribution(kg, prim_id);
+ } else { // Lamp
+ int lamp_id = -prim_id-1;
+ distribution_id = kernel_tex_fetch(__lamp_to_distribution, lamp_id);
+ }
+
+ kernel_assert((distribution_id >= 0) &&
+ (distribution_id < kernel_data.integrator.num_distribution));
+
+ /* compute picking pdf for this light */
+ if (kernel_data.integrator.use_light_bvh){
+ // Find mapping from distribution_id to node_id
+ int node_id = kernel_tex_fetch(__light_distribution_to_node,
+ distribution_id);
+ return light_bvh_pdf(kg, P, node_id);
+ } else {
+ const ccl_global KernelLightDistribution *kdistribution =
+ &kernel_tex_fetch(__light_distribution, distribution_id);
+ return kdistribution->area * kernel_data.integrator.pdf_inv_totarea;
+ }
+}
+
+/* picks a light and returns its index and the probability of picking it */
+ccl_device void light_distribution_sample(KernelGlobals *kg, float3 P,
+ float *randu, int *index, float *pdf)
+{
+ if (kernel_data.integrator.use_light_bvh){
+ *index = light_bvh_sample(kg, P, *randu, pdf);
+ } else {
+ *index = light_distribution_sample(kg, randu);
+ const ccl_global KernelLightDistribution *kdistribution =
+ &kernel_tex_fetch(__light_distribution, *index);
+ *pdf = kdistribution->area * kernel_data.integrator.pdf_inv_totarea;
+ }
+}
+
+
+/* picks a point on a light and computes the probability of picking this point*/
ccl_device
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list