Sign in to follow this  
B_old

Light Corona

Recommended Posts

Hello, I'm planning to add a corona effect to some of my lights. I guess the most straightforward way, is to use a textured billboard. What I'm curious about, is how to choose it's size ect. Because it should grow somehow if I move away from the light, right? Another thing that influences size, is how much of the light source is visible or something like that. If the light-source is occluded there is no corona although the billboard could be so big as to be seen despite the occluder. Is this generally handled with occlusion queries? Thanks for any tips.

Share this post


Link to post
Share on other sites
I can tell you only one thing. Look into the real life behavior. (That's the base of all effects).

How does corona behave? For example, if a light is occluded entirely, I think there is no corona at all. Corona is a lens effect (if I'm talking about the same thing as you are), and lens effects only occur, when the light source is visible, and of course, the effect is not occluded, since it arises "inside" the lens. And the strength of the effect depends on the amount of light that reaches the lens. So the less the (apparent) luminosity, the more "transparent" the effect is. For the size: That's an other question. My guess is that the size of the corona depends of luminosity (I would try something like this: radius = apparent_luminosity * constant1 + constant2). But since the transparency affects the visible size of the corona, I don't know. Try to look at films, real life, whatever to track down the behavior, and enchant your effect until it looks like that (or simply looks good enough).

And yup, occlusion test can be used for that.

I hope that helps.

Share this post


Link to post
Share on other sites
Yes, I think we are talking about the same thing. First I thought there might be some best practices for coronas or something like that. But you are right that it all probably depends on the lens involved.
But I'm sure there must exist some info on how to determine how much light reaches the lens. The part about occlusion queries I mean. How would/do you do it?

Share this post


Link to post
Share on other sites
I haven't used occlusion yet, but AFAIK it (or at least an extension of it) can be used to actually count the pixels, that pass the test. So draw a small sphere, or camera aligned circle during the test to the position of the light (size can be the same as the light-bulb, or just make it look/feel good), after everything else is drawn. The test will return the number of pixels that passed the test. This is not very precise of course and will produce a popping effect, but if you use some kind of interpolation between the frames, you can make it look good enough. I can't really think of more precise solutions.

And an important thing, the size of the effect (not the one used in the occlusion test) is in screen coordinates. Lens effect sizes are always in screen coordinates (since they arise inside the lens). So the distance of the light doesn't matter directly. All that matters is the apparent luminosity.

Share this post


Link to post
Share on other sites
Anybody who has used occlusion queries for this kind of thing?

Quote:
Original post by szecs
And an important thing, the size of the effect (not the one used in the occlusion test) is in screen coordinates. Lens effect sizes are always in screen coordinates (since they arise inside the lens). So the distance of the light doesn't matter directly. All that matters is the apparent luminosity.

Hm, I suppose you are right. But somehow I have this idea, that it would look right to have the size be dependent on the distance.

Share this post


Link to post
Share on other sites
Quote:
Original post by B_old
Anybody who has used occlusion queries for this kind of thing?


I've never implemented something like this before, but I'd imagine that occlusion queries are the way to go. They're pretty straightforward to use...you just may need to double buffer to avoid having to flush.

Share this post


Link to post
Share on other sites
Thanks for the tips and the link!

Quote:
Original post by MJP
They're pretty straightforward to use...you just may need to double buffer to avoid having to flush.

Hm, how do I find out whether a flush would be needed? Looking over this quickly, I couldn't find any info on such things.

[Edited by - B_old on April 26, 2010 2:34:09 AM]

Share this post


Link to post
Share on other sites
I implemented coronas recently using the depth buffer instead of occlusion queries.
I calculate the Z-buffer value of the center of the corona on the CPU, then every pixel of the corona compares this CPU-calculated value with the actual Z-value at the center of the corona. If the actual value is smaller, then the center is occluded and I use clip/texkill instruction to make the PS fail the alpha test and not draw anything.

On the CPU:
  copy depth buffer, bind to sampler
for each corona sprite
pos = center of the corona sprite
screenPos = pos * viewProjection
centerTexCoord = convert screenPos from post-proj space into texture space
centerDepth = screenPos.z / screenPos.w
put centerTexCoord and centerDepth into a uniform float4
draw the corona sprite
In the VS
  pos = usual billboard sprite stuff
In the PS
  color = usual PS stuff... get diffuse texture
expectedDepth = centerDepth uniform
actualDepth = tex2d( depthBuffer sampler, centerTexCoord uniform )
if( actualDepth < expectedDepth )
fail alpha test, i.e. don't draw this pixel

Share this post


Link to post
Share on other sites
Hodgman, it sounds like you either fully draw the coronas or you don't at all. There is no fading. Is that true, or did I get the wrong impression?

Also, in case anyone jumps aboard this thread, I'm still very much interested in the occlusion query stuff. I generally don't have a good grasp about the details. For example, do most people wait for the result in the current frame, or do they gather them later. I don't understand how that would work in case you use occlusion queries for culling, as the result might be worthless by the time it arrives.

Share this post


Link to post
Share on other sites
Quote:
Original post by B_old
Hodgman, it sounds like you either fully draw the coronas or you don't at all. There is no fading. Is that true, or did I get the wrong impression?
Yeah there's no fading. I was trying to replicate some coronas from a pre-rendered video, where the coronas didn't fade out (they were there one frame and gone the next) so this wasn't a problem for me.

You could extend it to support fading though, by taking more than one sample around the center point. e.g. a 4x4 sampling pattern would give you 16 levels of alpha.

With this Z-Buffer technique, you also always submit draw-calls for every corona, even if they're completely occluded, and then the PS chooses not to draw them at the last moment. So compared to occlusion culling, this uses more draw-calls, vertex processing and pixel processing, but can calculate occlusion for as many objects as you want without performing any occlusion queries.

I just thought I'd throw the idea out there because it was simpler for me to implement than occlusion queries.

Share this post


Link to post
Share on other sites
Hm ok, I see.
Sounds like an interesting idea and could suit me well, because I already use a depth-buffer for deferred stuff anyway. It's definitely something to keep in mind.
I wonder how many samples you could take before this method gets noticeable slower than something with occlusion queries...

Share this post


Link to post
Share on other sites
I haven't made coronas yet, but reading the topic my first idea was using the z buffer too, but not using one or more pixels' average z right in the middle, but doing almost like the tipical god ray implementation, only with one sampling 'around' the middle point - depending on the pixel's position and distance from the middle.

Share this post


Link to post
Share on other sites
So I gave occlusion a try. After rendering the g-buffer I issue the occlusion queries for the coronas, then I do all the lighting and shadowing stuff and at the end I gather the query results and render the coronas.
Performance is not bad at all. I believe I have noticeable lower fps for the first second before almost the same level as without occlusion queries is reached. Does this make sense?

Anyway, its working quite good. But I run into another practical problem. What exactly should I do with the number of pixels the query returns to me? Somehow I have to put that into relation with the distance of the light source.
Any ideas for a good formula? I'll have another look at the humus sample, but any input is welcome. And thanks for the help so far!

Share this post


Link to post
Share on other sites
Distance? I thought you agree, that it doesn't really count. The number of pixels count.

luminosity = num_returned_by_occlusion / MAX_PIXELS_CONSTANT_JUST_TO_MAKE_LOOK_GOOD + CONSTANT;

If the light is further, that means there are less pixels returned (because you have to draw the light object into the world with "world" sizes). the size mush match the size of the light source: light-bulb, explosion whatever. If have the sun as light source, than it can have constant size, since it's infinitely far away.

But I'm not sure if I'm right now...
Anyway, I guess you should simply try different formulas for yourself (I guess if someone here has the thing that you what, (s)he would have posted here already). No one will care, if it's not perfectly life-like. Just make it look/feel good/smooth.

Are you in shaders already?
If so: if you have a big light source, you might want to use bloom effect instead of simple sprites.

Share this post


Link to post
Share on other sites
Chm. In a way I agree in another I don't. I would, for example, expect an intense corona on far a away, but quite bright, light source even tough only a relatively few pixels are visible. Think of the beacon in a lighthouse for instance.

(I'm currently calculating the size and intensity of the corona on the cpu and then passing it along to my existing particle renderer.)

[Edited by - B_old on April 27, 2010 3:01:23 AM]

Share this post


Link to post
Share on other sites
Yup, but a light bulb at that distance would be almost invisible.
So different types of light has different I don't know it's scientific name. The total amount of light emitted by the emitter in all directions.

Apparent luminosity is the amount of light that reaches the eye/camera.

So you could do this:

apparent_luminosity = coefficient_depending_only_on_type_of_light * (num_returned_by_occlusion / MAX_PIXELS_CONSTANT_JUST_TO_MAKE_LOOK_GOOD + CONSTANT);

coefficient_depending_only_on_type_of_light is much greater for a stronger light (lighthouse) and much lower for a weaker light (candle).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this