Volumetric Lighting Only for Selected Objects

I have the following problem. Suppose I have a scene where (I simplify it very much) I have 2 objects: the sun and the planet. The sun, as is the custom of the sun, shines. The planet, of course not. I am skipping the shading issues now. What I want to do is render visible light rays coming out of my sun. So I am writing the code as follows:

from panda3d.core import *
from direct.showbase.ShowBase import ShowBase
from direct.filter.CommonFilters import CommonFilters
loadPrcFileData("", "textures-power-2 none")
loadPrcFileData("", "basic-shaders-only #t")
base = ShowBase()
props = WindowProperties()
props.setSize(base.pipe.getDisplayWidth(), base.pipe.getDisplayHeight())
base.win.requestProperties(props)
base.setBackgroundColor(0, 0, 0)
sun = base.loader.loadModel("ripple")
sun.reparentTo(base.render)
sun.setPos(-3, 0, 0)
planet = base.loader.loadModel("ripple")
planet.reparentTo(base.render)
planet.setPos(3, 0, 0)
filters = CommonFilters(base.win, base.cam)
filters.setVolumetricLighting(sun, 32, 0.5, 0.98, 0.1)
base.cam.setPos(0, -10, 0)
base.run()

Code effect:


(yes, I know suns are usually “a little” bigger than the planets orbiting them)
If we look at the left side (the sun) it is so far so good. But when we look at the right side (planet) we have a problem: the planet casts a “light shadow” from the sun!
Of course, I can try to change the parameters, for example like this:

filters.setVolumetricLighting(sun, 32, 1.0, 0.98, 0.01)

But no matter what I set I land somewhere in between I either still have an unwanted “light shadow” or I have to limit the volumetric lighting to a very modest glow around the sun:


Moreover, it is enough to move the planet object a little and already disturb the fragile balance of the power of volumetric lighting.
So the question is: is there an easy (read: without writing your own shader) way to turn on volumetric lighting only for selected objects? In the relatively modest documentation of this filter, I did not find such a possibility.

If you are using HDR with tone mapping, this is easier, because the sun can easily be thousands of times brighter than all the other objects in the framebuffer so the other objects will not contribute significantly to the volumetric lighting effect.

If you aren’t using an HDR framebuffer, what you need to do is mask out only the objects you want to use for volumetric lighting. I believe the built-in filter looks in the alpha channel for a mask. That means that you want all your objects to write 1 to the alpha channel if they should be casting volumetric rays, or 0 otherwise. You can use a ColorBlendAttrib with split color-alpha mode specification to achieve this. You can’t use a ColorWriteAttrib to achieve this because you still want other objects to be able to occlude the sun, and you can’t use a ColorScaleAttrib to mask out the alpha because that would ruin alpha blending.

Alternatively, you can use the stencil buffer or MRT to store this mask, but this will probably require you to modify the volumetric lighting shader.

1 Like

If you are not using alpha blending at all, and don’t have any transparency mode turned on, you can see the effect of the alpha-based masking:

planet.setAlphaScale(0.0)

But of course, this will hide the object if you turn on transparency.

1 Like

I don’t use HDR with tone mapping. Actually, maybe I could use it, but I have no experience with it yet.
At the moment I am not using alpha in this scene, so your simple solution from setAlphaScale is enough for me. In fact, if I wanted to turn on the alpha, then I would probably have to go to the ColorBlendAttrib (I don’t know how yet, but I’ll try to read or return to this thread).
I figured one more solution might be to render the entire scene omitting the object that is supposed to throw volumetric lighting, and then re-render only the object that is supposed to throw volumetric lighting. And some kind of overlap (probably with the off screen buffer). But here again I do not know exactly how, so I will probably stick to your proposed solution from setAlphaScale, which I currently treat as a solution.


Thank you!