GSoC 2022: Many Lights Sampling in Cycles X (Feedback Thread)

I’ve noticed a “strange” LT behavior. When I have only mesh lights - it works “as expected”. But when I have light entities (point lights, area lights, etc.) in the scene - enabling LT is kind of adding noise. This is an old scene but at least you can see what I mean. You can see that certain areas that were relatively clean without LT became quite noisy with the LT enabled. Maybe this has something to do with distribution of samples?

3 bounces, 100 samples, Light Tree OFF:

3 bounces, 100 samples, Light Tree ON:

UPDATE: Looks like this is a scene specific issue because I couldn’t reproduce it in other scenes.

UPDATE 2: I was finally able to reproduce it to an extent. In both cases enabling LT added visible noise.

The scene below is a simplification of a problem that I found in a production scene. There are 3 lights in this scene: mesh light (size 30km), area light (size 0,5m) and Nishita Sky. Area light is located inside a volume.

Without Light Tree all lights contribute to the scene, and the cone from area light is visible in volume:

With Light Tree enabled:

Here is a .blend file (disguised as txt, because this site does not support importing .blend files)
MLS_TEST_2.blend.txt (138.9 KB)

@JohnDow Without access to the scene, it can be hard for use to figure out what’s causing the issue. Are you able to share the scene?

I can reproduce your issue. From my understanding this is caused by the mesh lights being assigned really high importance (due to it’s size), resulting in the light tree directing samples towards the mesh lights even though they have basically no contribution to the scene due to their distance from the scene.

You can tell Cycles to not include the mesh lights in the light tree with this setting, but it may be worth while for someone on the Cycles team to look into it and see if there’s a bug.


Edit: The issue also appears to be related to the number of triangles on the mesh light. As the number of triangles increase (through things like subdivision), more samples get directed towards the mesh light up to a certain point. This can be observed when recreating the scene with a simple plane mesh light rather than a “planet ring” and using a subdivsion surface modifier on it.

However, I can only reproduce this issue in scenes with large meshes. When working with smaller meshes this “change of importance based on triangle count” is barely noticeable.

Video Demonstrating issue

3 Likes

Could be interesting to add some kind of “weight” or “importance” in the light settings?

I mean, you could want to avoid removing the mesh lights from the light tree for some reason, but don’t want the sytems to deliver too much performance to it, maybe a percentage or a 0-1 solution could work.

With that all the lights weight 1, like it is right now it you include everythingm, but if you define one light to 0.5 it will be 50% less “important” but it will still be properly sampled, this could mitigate the mesh light problem by allowing the user to lower the importance of such lights.

@Alaska thank you for investigating. Removing the mesh light from the light tree indeed improved the noise a lot. Thou in production scene this light have some ambient contribution to the scene, so I’ll probably need to hack it with some invisible, smaller light dome.

This scene is very similar to the previous one. The difference are:

  • removed giant mesh light
  • added little mesh light instances
  • added smaller volume
  • higher Sky emission

Issues I found with this scene:

  1. Massive slowdown (over 5min on my machine) when constructing a light tree before rendering starts. This is caused by instancing mesh lights. For confirmation I also tested instancing light objects and they seem to not cause any problems.
  2. Increased noise when rendered with light tree.

Light tree disabled
preprocessing time: 2 sec
rendering time: 2 min

Light tree enabled
preprocessing time: 5 min 29 sec
rendering time: 2 min

MLS_TEST_4.blend.txt (244.6 KB)

1 Like

@Alaska I can’t upload that scene, but I’m putting together a new one where I’ll try to reproduce the issue. If it works, then I’ll upload it.

[Deleted] Looks like the issue was resolved.

Lil’ request related to MLS: now that we can tackle dozens and dozens of lights in a scene, can we have array modifier on light? Pleeease?

1 Like

Please check after a21d948fd7ec, there was indeed a bug.

1 Like

This explanation gets a bit technical, but it’s not simply because the mesh lights get larger weights due to the size: in the light tree the importance is also scaled by the squared inverse distance, so mesh lights that lie far away shouldn’t have very large importance. I tested that scene, indeed whenever the area light gets weighted against another node in the light tree, the area light almost always outweighs the other.

The problem arises when that area light gets grouped with other mesh lights and forms a large node. In that case, we have (yet) no knowledge of where exactly inside that node the area light lies, so the distance measure is inaccurate. This also explains why subdivision worsens the problem (as @Alaska mentioned): the more triangles there are, the deeper the light tree is, so we traverse both children of any light tree node with maybe equal probability a few times, until we finally find the exact position of that area light and give it 99% weight, but the weight would already be too low (for example 0.5^5*1 ≈ 0.03).

In your specific scene, ideally we would like to separate the area light from all other mesh lights, but it is difficult because we group the light sources into axis-aligned boxs, and that area light kind of lies somewhere between the others. I’ve been mostly working on how to traverse the light tree better, and I think how to build the light tree could also be improved. The original paper just gives an equation for that without explaining why. But improving that would involve much intellectual effort.

Without the light tree, we have 0.5 probability sampling all the mesh lights, and 0.5 probability sampling all other lights (if any), which isn’t a good strategy in most cases, but works surprisingly well in your specific scene. Light tree won’t outperform in every single case, so my suggestion would be to choose whichever method works better, or as @Alaska said, set Emission Sampling as None for large light sources, because when the light source is large, the probability that it gets indirectly sampled is also large. It’s the small lights that need direct sampling more.

4 Likes

The massive slow down is caused by the large number of triangle lights in your scene (Roughly 83 million triangle lights). It doesn’t matter if they are instanced or not (although instanced mesh lights will probably be slower to construct a light tree from).

It takes a long time to process because that’s a lot of lights and the construction of the light tree is single threaded at the moment. The plan is to hopefully speed up tree building with multi-threading in the future, but at the time this is a limitation that people will need to deal with.

Also, just in case things aren’t clear. The number of triangles a mesh light has is the number of lights represented in the light tree. So a cube with 12 triangles, is 12 lights in the light tree.
Your scene contains roughly 16,000 tubes with roughly 5,000 triangles each. (If I understand correctly, mesh lights that emit out of their front and back are actually represented as two lights in the light tree, but that’s not super important.)


This scene contains a really complex light tree due to the large number of lights. As such, traversing down the tree to pick a light can be really slow, which will reduce the number of samples taken in a given time frame and can increase the noise.

There is also the possibility of some other factors affecting the noise. For example, you are using a shader on the mesh lights that change the alpha/brightness based on co-ordinates on the tubes. This may not be properly representing in the light tree and some mesh lights with low brightness/alpha may end up being over sampled and increasing the noise. (Note: Textures and complex shader node setups are not properly taken into account when constructing the light tree and this is another thing that is being investigated to see how it can be improved.)

1 Like

Instantiate the mesh light twice for front and back side was an earlier idea, but I found out that lights at the same position won’t be separated into different nodes, so that doesn’t make sense. Currently a mesh light that emits both sides are still considered a single light, just with a different axis and larger spread.

I guess the next most important thing is parallel tree building, instanced subtree is also important but the implementation doesn’t sound very straightforward. Although I won’t have time working on these problems for now.

4 Likes

Thank you both @weizhen and @Alaska for detailed explanations. I think I can understand the problem better. I’m trying to learn how to work with MLS and where its limitations are.

In the next test I ruled out the instancing and mesh lights. Same scene with two lights only (area light and Nishita Sky) with:

  • removed mesh light instances
  • added one mesh with diffuse shader and noise-driven roughness

In this example with MLS the mesh is slightly improved where it’s directly lit by area light but the volumes are more noisy overall. Especially in the parts lit by Nishita Sky.

Light tree disabled
rendering time: 2 min

Light tree enabled
rendering time: 2 min

MLS_TEST_5.blend.txt (157.7 KB)

This is an oversight. In most situations the sun in the Nishita sky isn’t properly represented in the light tree, resulting in fewer samples being directed towards the sun, resulting in an overall increase in noise. See ⚓ T103094 Cycles: The sun lamp from Nitisha sky is not included in the light tree.

This isn’t an issue when the light tree is disabled.

To my knowledge, this issue only impacts Nishita sky with the sun disc enabled.

1 Like

An example of the light tree at work:

Fast GI / Mesh lights

LT OFF: 175 samples
LT ON : 100 samples

Rendering time: ~13 sec

8 Likes

I made a post like this earlier and I thought I would do another one since a significant amount has changed with Many Lights Sampling.

Here’s a list of all limitations and quirks in Many Lights Sampling (and Emission Sampling) that I know of. I’ve also included some information people might find useful.


The Light Tree can't be enabled when using the HIP rendering backend

The HIP kernels fail to compile with the light tree, so it has been disabled while it’s being sorted out. The hope is that this will be fixed before the release of Blender 3.5.


Using the Light Tree will increase memory usage

When using the light tree, a light tree will be constructed and stored in memory, thus increasing your memory usage. The more lights you have, the more memory will be used.


Cycles scene initialization time is longer when using the Light Tree

When starting a render, a light tree needs to be constructed. This takes some processing and as a result the scene initialization times will be longer with the light tree.

Currently the light tree construction is single threaded, so it can be sped up with multi-threading, which is planned for the future.


Rendering with the Light Tree is slower than rendering without

When the light tree is enabled, you may notice that fixed sample count renders are slower. This is because each time a light is hit or picked during the rendering process, extra processing is done compared to rendering without the light tree, and so this slows down renders. But the hope is that the noise benefit of using the light tree will out weight the performance slow down.


Using instanced mesh lights doesn't lead to a benefit in memory consumption in the Light Tree

When using instancing, memory can be saved by reusing information. However, at this current point in time, the light tree doesn’t have native instancing support built in which means there’s no memory usage benefit in the light tree from using instancing.

I should note, instanced mesh lights will work with the light tree. It’s just the memory benefit that doesn’t “work”.

The hope is that support for instancing can be added in the future.


The Light Tree does not take into consideration occlusion

At the moment, the light tree builds a BVH for the lights in the scene. Each node in the BVH has a bunch of information in it, but it does not include occlusion information. And no geometry is included in the light BVH (other than mesh lights).

As a result of this, the Many Lights Sampling algorithm doesn’t know about any light occlusion by geometry and may accidentally over sampling certain lights occluded from a shading point.

This could be improved with a reinforcement learning system (similar to Path Guiding). But it’s currently not implemented and there are no immediate plans for this.

Image show casing issue

This is an extreme example. There is a point light on the right side of the wall. And a REALLY bright spot light on the left side of the wall. Due to the brightness of the spot light, Many Lights Sampling assigns a lot of samples to it. But this leads to a weird dark spot on the right with a lot of noise.

This is because the Many Lights Sampling system is picking the spot light a lot, even though the spot light is occluded by the wall. Because the Light Tree the Many Lights Sampling system is using doesn’t know that there’s a wall in the way.


When working with mesh lights, every triangle is a light

Every triangle in the scene that’s included in the light tree (by having a emission shader that’s bright enough to be considered a light) is a light in the light tree. I bring this up because it can be easy to forget the sheer number of mesh emitting lights you have in your scene because you might think each mesh is a light, but it is in fact every triangle. And this can impact the memory usage of the light tree and the initialization time of the light tree.


The Light Tree doesn't handle many complex node setups or textures in lights

The light tree uses approximations of lights during most of the process. And as such, many complex things like complex node setups or textured lights are ignored. This can result in a increase in noise as a light is treated as if it “casts light in a specific spot with a specific intensity”, when in fact it’s significantly different.

There are some ideas on how to improve this, but they’re currently not implemented.

Example of a textured light

In this example I have a normal white point light on the top and a bright teal point light below with a IES texture driving it’s output. You can see there’s a weird black spot around the teal lights emission point. This is because Many Lights Sampling is directing a lot of samples towards it because the light tree has it represented as a “full point light” rather than a point light with bits “turned off” with a texture.


The Light Tree doesn't work well with ray visibility

In Cycles you can adjust the “ray visibility” of objects. For example, you can make it so a light is visible to all materials other than diffuse materials.

The issue with this is that this property isn’t represented in the light tree which means certain lights with certain ray visibility option disabled will still be picked by the Many Lights Sampling algorithm and thus increase noise.

Example of issue

A scene with a diffuse surface and two lights. One light has the “visible to diffuse surfaces” setting disabled, but is still being selected by Many Lights Sampling and increasing noise.


Renders with the Light Tree might be a different brightness compared to without it

This is caused by the “clamping” setting in Cycles. It reduces the brightness of lights to avoid fireflies. But due to how it works, it ends up producing different results when you use a different light sampling strategy, and in the case of Many Lights Sampling that typically means there is an increase in brightness when using Many Lights Sampling with clamping compared to having Many Lights Sampling off with clamping.

You can find the setting for clamping here (setting it to 0 disables clamping):


The noise may suddenly change as you adjust light settings, position and rotation

As lights are changing in the scene, the light tree gets reconstructed to account for the changes. At a certain point, the changes you make might be large enough that it triggers the light tree construction system to construct a differently “shaped” light tree than what was previously being made. This will can change the noise in the scene.

Example video


Mesh lights below a certain brightness see a sudden increase in noise

Along with the Light Tree, a new “Emission Sampling” feature was added for mesh lights (usable with and without the Light Tree). It allows you to define whether or not the front and/or back side of the mesh should be sampled. Or even disable it entirely. By default it is set to “Auto” which will enable mesh light sampling for the front and back if the material is bright enough. Once the material is below a certain brightness, the emission sampling feature will act like the “None” option.

This can lead to an increase in noise as the mesh lights are no longer being sampled through “Next Event Estimation”.

The “Auto” features was added specifically to cull dim mesh lights from the light tree to reduce memory usage and initialization time in certain scenes.


The new Emission Sampling feature isn't working as you might expect

You may look at the description of the settings for “Emission Sampling” and read something like “None: Do not use this surface as a light for sampling”. And yet when you select this option, the light is still being sampled. Why is that?

What this setting does is decide whether or not the light should be used for Next Event Estimation sampling. If it’s set to none, then it won’t be used. However if the light is reached through some other method like forward path tracing, then it will still be sampled.


Using the light tree isn't guaranteed to reduce noise

The light tree is really useful for increasing the probability of samples going towards lights that are more beneficial for the current shading point. And this relies on there being a meaningful difference between the importance of different lights and nodes in the light tree. If there is no meaningful difference between the importances of different lights and nodes, then there’s no way for the light tree to help out. This case is rare, but it can happen.

Also, simple scenes, specifically scenes with coloured lights, can see a increase in noise when using the light tree.

Example of a simple scene that sees a increase in noise due to the light tree

This is a simple scene. One teal light and one red light. This was rendered at 4 samples per pixel.
The image on the left (light tree on) is noiser than the image on the right (light tree off)

Also, the light tree is only really useful for scenes with materials that scatter light. If the entire scene is made of perfect mirrors and perfect glass, where no scatter occurs, then there will be no benefit of using the light tree as the useful part of the light tree function will never get used.

There are also some other quirks I have shared above (ray visibility, textures, etc) that can negatively impact the noise when using the light tree.


In various situations the current Light Tree/Many Lights Samplings implementation is nosier than other versions from other renders, or even the Many Lights Sampling project from just a few months ago

Some adaptations have been made to the Many Lights Sampling system to fix issues with the implementation used in Cycles a few months ago. These adaptations have lead to a reduction in effectiveness of the light tree in some scenes and as a result increased noise.


12 Likes

Interesting. Here is an example of that in action:

10 Likes

Noticeably cleaner ! what about the light tree build overhead ?

I’ve not had any problems with the light tree building. It takes 1-2 seconds max.