Simple 2-Sided Shading

I’ve been working on some single vertex-shader displacement shaders, that use shading based on the fragment’s distance from an arbitrary point instead of proper lighting with surface normals etc. Here’s an example of the kind of thing I mean:

It’s quite effective, in a stylised kind of way, and obviously a lot more efficient than more realistic lighting calculations, since I don’t have to calculate normals for the displaced vertices. What I’d like to know though, is if it would be possible to apply different base colours to the forward and backward-facing sides of each strip, without rendering the whole thing twice with back and front-face culling enabled.

Anyone any thoughts on a simple GLSL-only way to decide if a particular fragment is facing forwards or backwards, so I can colour it accordingly? I’m aware this may just not be possible in GLSL alone, but I’d love to know either way.

Cheers,

a|x
http://machinesdontcare.wordpress.com

You’ll want to check the bool gl_FrontFacing in the fragment shader. :slight_smile:

Another way is to enable the GL_VERTEX_PROGRAM_TWO_SIDE_ARB state and write to the the gl_FrontColor and gl_BackColor built-in varyings in vertex shader. In that case reading from the gl_Color inside the pixel shader will return color for appropriate side.

I once tried that method, but it resulted in a considerably large performance hit. Branching on gl_FrontFacing was much more efficient for some unknown reason. I’m using an NVIDIA 8800 GTS.

It is possible that the GF8800 does not have direct hw support for the double sided colors anymore and emulates them using two ordinary varyings and the front facing register.

I did not need that functionality over the past few years so I do not know what the current state of performance and compatibility of both approaches is.

Thanks very much for all your replies, guys!

I will try both methods, and see which works best.

Thanks again,

a|x

Must be some kind of quirk of Quartz Composer’s OpenGL setup or something, but if I use
gl_FrontFacing
in the fragment shader, my framerate drops from 60fps to about 5fps.
I also get weird things happening like parts of the surface flashing on and off (presumably because it can’t decide if it’s front-facing or not).

The other method, using gl_FrontColor and gl_BackColor in the VS doesn’t work (I just get the front color on both sides), so I assume that QC has 2-sided lighting turned off.

Of well; another feature request, I think…

a|x

What card do you have? On older hw the driver might switch to sw emulation to handle the gl_FrontFacing varying.

The other method, using gl_FrontColor and gl_BackColor in the VS doesn’t work (I just get the front color on both sides), so I assume that QC has 2-sided lighting turned off.

That is almost certain. The shader must be aware that the the double sided colors are enabled so that feature would be probably provided as some toggle. I never worked with Quartz Composer, does it expose any way which can be used to directly manipulate the OpenGL context?

As temporary solution you can send eye space normal and fragment position using ordinary varyings and use them to decide the probably side. Of course the result is less reliable than the one you can get from the hw.

Hi Komat,

I’ve got an ATI Radeon X1600 256mb, running on my MacBook Pro/MacOS 10.5.3.
I think you’re right about the driver falling back to sw- would explain the drastic framerate drop, especially as the vertex shader is doing some heavy vertex-displacement stuff, which would quickly bog-down the CPU.

I may try the normal method. Do you happen to have a snippet of code to take interpolated normal and fragment position and use that to decide if the fragment is forward or back-facing?

Cheers,

a|x

The idea is as follows:

First you calculate normal of the triangle. Because you are doing displacement, you will have to calculate it inside the shader. For example by providing each vertex with additional attributes containing positions of the two remaining vertices within the same triangle in proper order. This way you can replicate the displacement for all of them and calculate the triangle normal.

Then you take object space position of point within the triangle (for example average of vertex positions) and calculate direction vector from object space position of the camera (retrieved from gl_ModelViewMatrixInverse matrix) towards that point.

When dot product between the triangle normal and the direction vector is positive, you are looking at back facing side. Because both constants do not change across the triangle, you can calculate that in the vertex shader and send only the result to the pixel shader.

Yes triangle normals are sufficient to do culling but I remember that toneburst is essentially working with a tool called Quartz Composer; I don’t know if he will be able to retrieve such information like triangle vertices coordinates.

Computing normals can otherwise be done is the fragment shader derivating texture coordinates using dFdx/dFdy but yes it is much less efficient (as said in one of his a previous posts).

Hi again Komat.

Thanks for the reply.

Unfortunately, I don’t have a way of accessing triangle information, since I’m only able to use pure GLSL shader programs. On the other hand, it’s usually possible to calculate the normals inside the vertex shader. This is quite expensive though, which is why I chose to use a very simple simulated lighting effect, without normals on this occasion.

…on the other hand, its good to have a method of of implementing 2-sided materials, so I’ll definitely keep this in mind in the future.

Thanks very much for your patient explanation. As you’ve probably guessed, I’m new to all this, so any help and explanation is very-much appreciated.

Thanks again,

a|x
http://machinesdontcare.wordpress.com

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.