[Soc-2018-dev] Weekly Report #10 - Many Light Sampling

Erik Englesson erikenglesson at gmail.com
Fri Jul 20 23:02:07 CEST 2018


Hi all,

Here is my weekly report:

*This week* I have

   - Added support for several emitters per leaf node in the light tree
   - Debugged mesh light render

*Several emitters per leaf*

This makes it possible for leaf nodes in the light tree to have more than
one emitter, which was not supported before. This required a change in the
stopping criteria in the build algorithm and a change to the sampling
algorithm if a leaf with several nodes was picked in the tree traversal.

The stopping criteria were changed so that it stops if there is only one
emitter left or if the cost of splitting the node into two children is
always larger than the energy of the node. A maximum number of emitters per
leaf node was also added to not get leaves with too many nodes(makes
sampling more expensive, see below). I currently set it to 64, but this
will most probably have to be tweaked.

If a leaf with several emitters is found in the tree traversal during
sampling then one of them is chosen probabilistically based on the
importance metric of each emitter. To be more specific, a Cumulative
Distribution Function(CDF) is created based on the importance metric which
is then sampled. This was a bit tricker than I first thought for two
reasons:
1. The node only stores the information needed to be able to calculate the
importance metric for the aggregate of all lights within it not for each
light separately.
2. The CDF depends on the shading point so it is not possible to
precalculate it and reuse it several times as we do with the other CDFs.

1 was solved with another device array with the appropriate information.

I first thought 2 would need dynamic allocation since the CDF depends on
each shading point and it is not really feasible to preallocate a CDF per
leaf with several emitters since several threads could read and write to
that same location. I was able to come up with a solution that does a
little bit more calculations(N + O(N) importance evaluations instead of N +
O(log(N) ) but does not need dynamic allocation.

This work can be found in the following commit
<https://developer.blender.org/rBbeef4874d330>.

*Debugged mesh light render*

One of the test scenes I use looked a bit strange to me. The scene is just
a cube that has been turned into a mesh light that is just above a large
plane. Here is the scene rendered(branched path tracing with 128 AA samples
and with a splitting threshold of 0.001) with the light tree:
*https://drive.google.com/file/d/1LQCNoDz-1Ty1TtkroKc7cRITWs6rN4FO/view?usp=sharing*
<https://drive.google.com/file/d/1LQCNoDz-1Ty1TtkroKc7cRITWs6rN4FO/view?usp=sharing>

What I found strange was the "discontinuities" and the rings below the mesh
light cube.

Here is a "ground truth" solution(branched path tracing with 1024 mesh
light samples and 329 AA samples) without using the light tree:
*https://drive.google.com/file/d/1-LUOaYhe_rKj9TPhrfHRZMDA8vXUyd1E/view?usp=sharing*
<https://drive.google.com/file/d/1-LUOaYhe_rKj9TPhrfHRZMDA8vXUyd1E/view?usp=sharing>

It is interesting to see that some of the discontinuities are also present
in the ground truth image. However, the rings on the plane are not and at
certain places, the light tree version is darker/brighter than the other.

I created an even simpler scene to debug this where the cube stands flat on
the plane and only one face is an emitter. Here is a normal render of it
with splitting threshold 0.001:

*https://drive.google.com/file/d/1rYc6pllQI_bUBreF7PtiVDPKStQ8GKVh/view?usp=sharing
<https://drive.google.com/file/d/1rYc6pllQI_bUBreF7PtiVDPKStQ8GKVh/view?usp=sharing>*

Notice that it is possible to see a discontinuity that looks like a
half-sphere in this image too.

Here is a debug render that shows the number of lights that tried to be
sampled:

*https://drive.google.com/file/d/1Sw7wDhX7XSR3oBGUyVu_XdvMIJ3W6-ie/view?usp=sharing
<https://drive.google.com/file/d/1Sw7wDhX7XSR3oBGUyVu_XdvMIJ3W6-ie/view?usp=sharing>*

Red = 0, Green = 1, Blue = 2 sampled lights. Note that the emitting face of
the cube is actually two emitters, one for each triangle. I have spent some
time to understand why it looks like it does, e.g. the straight line
separating the green and the red instead of something more like a pie
shape. This seems to come from the last term in eq 3 where the border is
where it switches from 0 to cos(theta').

I think this clearly shows that the half-sphere shaped discontinuity comes
from a different number of lights sampled. I found this comment in the
paper:
"*Intuition suggests that jumps in the number of shaded lights could lead
to discontinuities, but in practice the transitions produced by the
variance based heuristic (Section 5.4) are smooth enough to render these
transitions invisible. In practice we are further assisted by adaptive
pixel sampling which equalizes the variance across the image. We only used
fixed numbers of camera samples for the results presented in this paper.*"

This leads me to think that either there is a bug in the heuristic or the
adaptive pixel sampling is helping them more than they think. Mesh lights
might be very prone to these types of artifacts and I think the authors
mention that they do not use splitting when these types of lights are used.

The only thing that is a bit unclear in the importance heuristic is the "a"
and "b" variables in equation 8 and 9 in the paper
<http://www.aconty.com/pdf/many-lights-hpg2018.pdf>. What I do now is to
take the distance to the cluster center. Take "a" to be the distance minus
the radius of the bounding sphere and "b" to be the distance plus the
radius. If this is correct, then what should be done when the shading point
is inside the bounding sphere? Then "a" will be negative which will result
in nans later in a square root. It is not possible to clamp it to zero
either because then the integral won't converge. I force splitting to
happen if the shading point is inside the bounding sphere. (Which is why we
see the rings show up. The discontinuity is the border between points
inside and outside the bounding sphere.)

Using a larger splitting threshold(0.85) seems to smooth out some of these
discontinuities:
https://drive.google.com/file/d/1o8-zTtVb6TJTIyToWn_HOiBg4Q7M6qlZ/view?usp=sharing
https://drive.google.com/file/d/10177GICViak_IxylVijzC8VmYm5KL8AL/view?usp=sharing

Here is a debug render of the original scene:
https://drive.google.com/file/d/1Og8Dg2MD0TQT7vPFESXlpixobUGgL15p/view?usp=sharing
which also shows where the rings come from.

*Next week* I want to continue debugging the current implementation. I will
first double-check the splitting heuristic. If there is nothing wrong then
I will have to consider coming up with something to smooth out the
discontinuities since we cannot depend on adaptive sampling(does not exist
in Cycles as far as I know). I would also like to understand where the
differences in brightness in ground truth compared to the light tree render
comes from. Also, it would be good to try out the volume and subsurface
code branches to make sure it does something reasonable there.

Have a great weekend!

Thanks,
Erik
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.blender.org/pipermail/soc-2018-dev/attachments/20180720/7a6b58d7/attachment-0001.html>


More information about the Soc-2018-dev mailing list