Improving Light Propagation (Elemantal Demo reamke with LPV)

Hi Unreal Developers!

I created a blog post explaining how you can use real-time area lights inside light propagation volumes and together with that a video showcasing LPV area light injection in action inside the Elemental Demo.

is the video:

While working on this I had some ideas on how we could improve LPV. Since my knowledge of the engine code is currently not enough to integrate it myself, I hope sharing it with the community might
start an interesting thread and maybe eventually someone from the community, or maybe even Epic, could implement it, if any good ideas come to life.

Most of you probably know that point and spot lights are not supported with LPV. is an example of a green colored spotlight inside a light propagation volume:

And is the same images, only now there is light injected into the LPV from an invisible area light with the same color as the spot light:

This already lights op the scene very well dynamically. The only problem is that it doesn’t take the color from the wall into account, which is the most important part about global illumination. So what if
we make every object in the scene an area light, and it uses the base color as injected emissive color multiplied with the brightness and color of the light and in the end multiplied with the shadow map.
This way only the lit part of an object will emit light.

I could not make a good demo for this, since there is no shadow map available inside the material editor. But I kind of used the idea (except for the shadowing part) with the flags in my version of the Elemental demo:

As you can see, the pillar in the front has a bit of a red overlay. This comes from the red flag on the right of the screen that injects its red color into the LPV using an area light material. I also did this on the left side with the snow and ice.
This is the reason it looks more white/blue compared to the original demo. All this cost a lot of time to set up per object, but it would be easy to automate this.

The only thing missing is that the direction of the light is not changing the direction of the indirect lighting.

I also noticed that objects that have a completely different look on all side have a huge change of showing LPV artifacts, since not every little detail is picked up by the LPV rendering. Maybe it would be possible
to bake a volume texture per object during light baking, kind of like the distance field ambient occlusion, and use this info to inject every mesh into the lpv volume with the intensity based on how well the volume is lit.

Thanks for reading, I hope I gave some of you good ideas. Please let me know why you think this could work, or why it won’t work at all.

is my blog post for everyone who wants to check out how to set up area lights, or just download an example:


Nice, glad to see this finally be posted Roel :slight_smile: Good stuff!

I heard that Epic might integrate the full LPVs once Lionhead gave them all the code. Lionheads integration is far ahead from what we have now…but since their title has not shipped yet, they probably still are under NDA and cant share their stuff fully with Epic.
So…in general, I would wait for that and then start looking into whats missing. Right now, its not really more than a first test integration.

Cool! I didn’t know that :).

Thanks Os!

This is a very cool thread Roel.

This is actually what’s happening right now =) By injecting direct light only (what’s visible from shadowmap) and propagating once, you get one bounce of diffuse GI. What you really want is multiple bounces of diffuse GI, things like those red flags that aren’t in direct light need to bounce lighting too. A second diffuse bounce could be accomplished by applying the first bounce LPV results to geometry and injecting it again, then propagating again. However at that point there will be a ton of error from diffusion in the fixed grid, plus lack of detailed local occlusion increases the leaking, and you have the cost of doing the propagation multiple times.

The only improvements from Lionhead that we haven’t integrated (as of their blog post) are sky shadowing from the LPV and a whole bunch of Xbox One optimizations. We have been going in the Distance Field AO direction with dynamic sky shadowing so didn’t have time to integrate it. They could co-exist though.

I wonder what the timeline is on improving the LPV integration at the moment (like the improvements Martin mentioned in the rendering update stream from April 10th)? Is it something you guys wanna tackle next year or rather in the next couple of months?

Thanks .

So is the reason we don’t have light propagation for point and spot lights that it is heavy to multiply the volume texture with all the shadow information from every light? Or is there another reason?

It would be cool if we can just have any light enabled, even if it is expensive. In my game I don’t have a directional light, because it is all inside, and the wall are thick enough to support this feature. I can make it so there are never too many lights in the
scene, and stream out everything I don’t need anymore. And if shadowing is the real issue, couldn’t we make it an option. So if we leave dynamic shadows off on a light, it will still inject itself into the
volume, which causes leaking, but in some case that does not even matter. I could live with building my game around those limitations.

BTW, there are 2 bugs you might want to look into:
-When you apply an area light material onto a particle emitter and then turn on shadow casting for that particle emitter, the engine crashes instantly.
-Turning on “Force no precomputed lighting” in the world settings will make all reflection captures render black. Only SSR will work.

And for anyone interested, I added the link to the area light blog in the post:

+1 on that. There are always cases where performance isn’t too important.

I asked Martin what the improvements were he had in mind, will see soon.

I think it just isn’t implemented yet. It will certainly cost more to inject those lights and render reflective shadowmaps for them instead of the usual depth-only shadowmaps used by Movable lights but it can be done.

LPV uses the shadowing information (reflective shadowmaps) to know where to inject into the volume, so you can’t really do it with unshadowed lights.

Thanks for the explanation ! I never worked with reflective shadow maps before, looks like one of those techniques I have to implement myself at some point to fully understand it. I more or less do graphical “programming” for fun, so I’m not really a pro, or even a programmer :P.

The game I’m currently working on will have completely dynamic lighting from a couple of point and spot lights. There is just one small level. The only thing I need is really good lighting to make sure the art will look almost as good as with baked lighting. Since the whole game is about turning on and off the couple of lights in the level, and some of the lights are moving around, it caan’t be baked. The time frame is about 14 months for the game, so I will just slowely integrate the lpv when the point/spot lighting becomes available. For prototyping it does not matter too much that there is no indirect lighting for the dynamic lights. I will also post in this thread when I run into any problems along the way, like for example the following:
-Turning on tessellation “relocates” the injection. You can see artifacts popping up in strange places and it is mainly not anymore at the location you are injecting it.

I will let you guys now as soon as there is anything interesting to show from the game :slight_smile:

Roel, this is nice work.

answered almost evyerthing but I can add some details.

> I also noticed that objects that have a completely different look on all
> side have a huge change of showing LPV artifacts, since not every little
> detail is picked up by the LPV rendering

The reflective shadow maps resolution is low for better performance. If you disable small objects you can improve performance and reduce artifacts.
The GIReplace material node can be used to output a more constant color for GI - again for improved performance and to reduce artifacts.
I noticed you talked about it in the other thread so you are aware of it:

> You might have noticed the GIReplace node. This one is really important
> for artistic control. By having a different scalar parameter node for direct
> and indirect lighting we can control the amount of bloom and area light
> injection separately. Bloom is a post process effect that check the brightness
> of the pixel being rendered. By default in Unreal, every value higher than
> 1 will end up glowing. The higher the value the more it glows. This is why
> we need to seperate it from the light injection. We don’t want the light
> injection to also boost the glow effect.

The part about Gi is correct but the bloom is only controlled by postprocess settings (Bloom intensity, threshold, eye adaptation) and the brightness of the content
you look at. having a brighter scenecolor can result in [more] bloom.

You can fake some light from point and spot lights adding an emissive sphere at the light position but it might alias/jump if you move it over time.
There is a setting on the material to enabled the injection of the emissive light. This will not result in a bounce like for directional lights.

The reasons for not having the feature on other light types than directional:

  • It’s possible but wasn’t done yet as we have been working on many other things
  • It will be quite slow as it needs to render each object in the attenuation
    radius for each light it is enabled, sometimes even more often (think of cube maps for point lights)
  • It adds complexity to the implementation and it’s better we fix and improve other areas first

I will add the tessellation issue to the bug list - maybe we should just use the material without tessellation.

> -Don’t use this material on particles, it will make the engine crash.

There is some known bug related to the flags on the material. We will look into that soon.

Lionhead is improving the system further and we hope to integrate and update the code from them soon.
We also look into bugs and performance on our side. Hopefully we also can implement some features to make it a more complete solution.
I personally would like to have multiple cascades and fast scaling of the LPV volume should be without artifacts (old values get projected to the wrong spots).

Keep us updated on your work!


Thanks Martin, I have changed it in my blog :). I have run into another issue, my game is completely dark(literally black) in the beginning, so I can’t use the prebaked reflection captures.
And SSR is a nice start, but brakes quickly, and without the static fallback it all looks weird.

I’m currently looking into the VXGI, since the game will be in production for at least a year till a good beta version. This would fix all the issues we are having with lighting and reflection.
The environment is small I am going to assume it will even run well enough on the 800 and maybe even 700 NVidia cards.

I red in another thread that you guys are going to implement it by the time it is more compatible with other platforms. I’m also trying to get in contact with the NVidia GameWorks sales team
to see what kind of offers they have.

It would be great if their plugins were on the Unreal Marketplace, even if the are expensive or want to have a revenue share.

Thanks for all the feedback, and I will keep you up to date on the progress of the game!