A while ago when I was implementing shadow volumes in my rendering engine I came up with an algorithm to compute a given light's bounding screen-rectangle. According to my tests, it works pretty darn well, however, having said that I'm still wondering if there are cases out there that could break it.
Anyway here it is, I would appreciate any commments:

Why would I :p ?
I know by doing so it might incur a performance hit, but keep in mind that they're called once a frame which doesn't matter that much if any at all.
Seriously though, what do you think of this approach? Is it flawed or what?

Humus

06-10-2005, 03:40 PM

If I understand what you're doing correctly, you're basically seeing the light as a 2D billboard at the light's position so to speak, and figuring out the extents of that in screenspace. If that's the case, then it's flawed. That's what I tried first too, until I realized it doesn't work when you get close to the light. It will return a slightly smaller rectangle than you need. I'd draw a picture if I wasn't too lazy.

Java Cool Dude

06-10-2005, 04:44 PM

You're correct, my approach is to consider the light's scissor-rectangle as a billboard centered around the source.
Now regarding the glitch that you mentioned, a simple check on the distance from the viewer to the light source could easily prevent it ;)

Thanks for the link mate, but I've already touched on that and figured that my method is simpler and requires far less computations ;)

SirKnight

06-10-2005, 10:04 PM

Oh and knackered's advice is good, glGet really should be taken out. For debugging/prototyping it's fine, but once your algorithm is working, rip those things out. If you were doing your 3d in software, say using MESA, then using glGet is fine. However, in hardware, functions like glGet have a pretty big cost with them and should not be used in production code.

Originally posted by Java Cool Dude:
You're correct, my approach is to consider the light's scissor-rectangle as a billboard centered around the source.
Now regarding the glitch that you mentioned, a simple check on the distance from the viewer to the light source could easily prevent it ;)

if(cameraPosition.getDistance(lightPos) - lightRange <= EPSILON)
return viewport;What's the value of EPSILON? Something close to zero I guess? Then you're only taking care of the case where you're within the light radius. It's actually broken regardless of distance, though in practice it may work when you're far from the light.

This is what I mean:
http://www.humus.ca/temp/flaw.png

The dashed line with what you get, while the solid line is what you want.

Java Cool Dude

06-11-2005, 08:36 PM

You got me there :p

knackered

06-12-2005, 11:02 AM

Originally posted by M/\dm/\n:
Kinda wild guess, but arn't modelview/modelviewprojection matrices stored on CPU side, at least one copy???In reality that's a possibility, but it's a server state not a client state, so it's just as possible that it's not cached in system memory. Imagine if an implementation decided to take advantage of the T&L bits on the card to accelerate matrix stack multiplications, in that case it would be impossible to keep a system memory cache of the current matrix stack.

Ventura

06-12-2005, 11:14 PM

The simplest method i used before, without having to get my head round lengyels method, was to keep a global list of sample points (~12) on the front side of a unit sphere.

Then manually scale and transform these points to where your light is, and then transform into screen space, and assemble and clip a rectangle from it.

You can be adaptive with your sample count at distance, but you have to be careful about -ve projections and stuff.

This method worked perfectly for my stencil shadow engine, its not as elegant as lengeyls but iirc he had a few sqrt's in there too. It also will result in a larger scissor rect in some cases.

fpo

06-14-2005, 09:19 AM

Originally posted by SirKnight:
Or this http://www.gamasutra.com/features/20021011/lengyel_06.htm

(This is also in Eric's 'Math for 3d game prog & comp gfx' book).

-SirKnightThanks for the reference SirKnight. Implemented it and it works fine. Just equation 29 has C instead of L in fromula. But I have a quesion ... what value of 'e' must we use in eq 39? I'm using 1.2 and work ok but 1.0 will fail and clip more than it should. He does not say much about the 'e' parameter...

SirKnight

06-14-2005, 10:32 AM

You know I'm confused about 'e' too. :) I thought it might have been the near clip plane distance b/c of what that one diagram shows 'e' to be.

EDIT: Oh yeah you're right, eq 29 is wrong. I never noticed that in this webpage article. In his book he has it right however.

-SirKnight

castano

06-14-2005, 11:03 AM

I've used the formulas from the gamasutra article without problems. It's true that they are more complex than they need to be, but it's been working fine for me.

Also, don't forget to compute also the depth bounds and use NV_depth_bounds to safe fillrate. On non nvidia hardware you can also use the near and far clip planes, but in that case you will have to adjust them to avoid z fighting or use polygon offset instead.

/**
* Compute the screenspace bounds of the light.
*
* This is just Eric Lengyel scissor optimization:
* http://www.gamasutra.com/features/20021011/lengyel_06.htm
*
* The equations in the Gamasutra article, while correct, are more complicated
* than they need to be. Equation (38) can be replaced by the much simpler
* formula P = L - rN. If you have the second edition of Mathematics for 3D
* Game Programming and Computer Graphics, an updated derivation appears in
* Section 10.7.*
* -- Eric Lengyel
*
* Hmm.. I only have the first edition, but the derivation should be pretty
* easy. In any case this doesn't seem to be an important optimization.
**/
bool PiLight::ComputeLightBounds(const PiViewport * viewport, BBox * box) const {
piDebugCheck( viewport != NULL );
piDebugCheck( viewport->cam != NULL );
piDebugCheck( box != NULL );

Using 'e' as 2 in my code makes scissor much bigger than it could be. Using 1.2 works fine for my simple test scene with 3 different lights.

SirKnight

06-14-2005, 02:40 PM

This demo here does some calcs to compute the scissor box and it looks pretty good. Here is the link: http://developer.nvidia.com/object/fast_shadow_volumes.html

I don't think they are using eric's method, at least it doesn't look like it to me with a quick glance. I'm not sure if this demo does all of the methods possible to have the fastest shadow volume rendering but I know it does quite a bit and does run good.

-SirKnight

Java Cool Dude

06-14-2005, 04:22 PM

For some reason the method described in your link, SirKnight, returns a bounding rectangle a bit bigger than what it should be. Have you tried it?

fpo

06-14-2005, 07:39 PM

Ok, here is my code based on Eric's article and I must say it works fine and generate quite small scissor rectangles. Should be easy to copy/paste into your own code as it only uses standard C objects (apart for the 4 component pVector object... replace with your own vector object there).