"Second" backface culling

Hi!

Backface culling in hardware is of course pretty simple using GL_CULL_FACE but what if I have the following situation:

The pass I want to render is for example a bumpmapping pass. So I’m rendering the scene from the camera’s point of view using backface culling. That will cull the faces that are not visible for the camera. But I’m still needing backface culling for my lightsource so that the bumpmap will only be applied to the faces that are visible to the light source in order to save fillrate.
I was thinking of using vertex shaders but that probably won’t work since you don’t have access to complete faces but only to vertices.

Does anyone have an idea how to do this?

Thanks in advance
LaBasX2

“True” 2nd backface culling is rather impossible but you can save the fillrate by using alpha test. So in case of additive lighting you could calculate an average of rgb in your output color (using dot product) and output it as an alpha for alpha test. This way not lit regions (black) will be “culled” by the alpha test.

Coop

I would do this in software. alpha test may screw up your scene.

Use the usual dot product between light vector and face normal.

V-man

But this way you have to access your geometry with CPU to calculate dot products (light vector depends on vertices). You may need a system copy of the geometry if it’s in AGP or video mem. You also have to dynamically build new index arrays. For me it’s too complicated.
With alpha test you only need to setup the alpha test stuff and render your optimized, stripified, “VARed”, “VAOed” geometry as usual.

Coop

Here is an idea. Use texkill. Set one of the texture coordinates to be the dot product of the light and surface vectors, kill any fragments where this is 0 or less. This eats a TMU however, yum.

> alpha test may screw up your scene.

Alpha test was the solution I immediately thought of when reading the problem statement. I don’t understand why it would screw up your scene in the case described; it should work fine.

Whether alpha test ACTUALLY saves fill rate varies between graphics cards, though.

Thanks for your help!

Alpha testing and texkill sound like good ideas. I’ll give it a try.

LaBasX2

Originally posted by jwatte:
[b]> alpha test may screw up your scene.

Alpha test was the solution I immediately thought of when reading the problem statement. I don’t understand why it would screw up your scene in the case described; it should work fine.

Whether alpha test ACTUALLY saves fill rate varies between graphics cards, though.[/b]

If for instance the light is somewhere in front of you and you have an object in front as well, you may see through the back faces that are perfectly dark (the front and lit faces will be visible)

I’m thinking of a 1 pass algorithm here.

Seems obvious to me.

V-man

Okay, gettin’ niggly with quoting from the initial question: “the pass I want to render…” So I feel it’s pretty clear to assume it’s not a single-pass situation.

Anyway, if that’s the way to save fill rate, I have an even better suggestion:

glCullFace( GL_FRONT_AND_BACK );

:slight_smile:

I was just thinking of another way that could work. One could store the face normals with the vertices and use a vertex program to do the light/normal dotproduct. If it is smaller than zero, the vertex is moved to a fixed position, for example 0,0,0. That way unlighted faces would become zero-area faces and would thus cost no fillrate…
Should be working, or am I missing something here?

Thanks
LaBasX2

You would have to duplicate your vertices for every face, because each face has its own normal. So you practically end with glDrawArrays instead of glDrawElements, vertices cannot be reused, vertex cache is not used and you’ll probably loose more this way than you save with your culling.

Coop

Thanks coop, yes that’s basically right. But it depends on the sort of application. For a Doom3-style engine that has a low polycount but very hight fillrate requirements saving the fillrate will definately bring more than caching vertices. But for a terrain engine, it would probably be the the other way round.

Thanks
LaBasX2