From: Hugues De Keyzer (hugues++at++depinxi.be)
Date: 09/08/2005 08:29:13
Vincent Pasqualato wrote:
> Hi !
>
> Trying to combine a shader program written in GLSL with a Performer scene
> graph, we discovered that rendering an flt object with faces which are
> flats (no gouraud/interpolation, no vertex normals) gives us strange
> results : The flt loader seems to try some computation of vertex normals,
> because there is a variation of the normal we get from Open GL (in
> gl_Normal parameter of the shader program) across the faces. Plus, this
> interpolation is buggy, resulting in very strange patterns of normals on
> the object. If we transform our object in gouraud, and pre-compute the
> vertex normals, the rendering is OK, except we don't get the flat faces
> we would want. Does anyone have a suggestion about this behaviour ? Is
> there an option to deactivate this normal computation ? Or is it correct,
> assuming the classic OpenGL pipeline doesn't take into account vertex
> normals when rendering flat faces ?
I suppose you are using varying variables to transmit the normal vector to the fragment shader where you compute per-fragment lighting. Actually, varying variables are always interpolated between vertices, as are texture coordinates, even if flatshading is enabled. What happens here is that because your geometry uses flatshading, the normals are specified per-primitive and sent down with the closing vertex. So, in a triangle strip for example, each vertex has a normal except the first two. If these normals are interpolated across the face in a varying variable and used to compute lighting, the results are incorrect because the normals specified for flatshading are used to smoothshade.
Fortunately, there are two ways to prevent this.
The first way consist in tricking OpenGL to not interpolate the normals per-vertex but per-face. Flatshading ensures that the color of the fragments of a primitive is constant across the whole primitive. That is just what it does. It doesn't interpolate the color. So let's use the color! There are 4 built-in varying variables that specify color and that will be interpolated according to the shading model. These are:
gl_FrontColor
gl_BackColor
gl_FrontSecondaryColor
gl_BackSecondaryColor
The secondary colors are normally used to store specular color when separate specular is used. To store our normal in this, we range-compress it like in a normalmap:
color = vec4(normal / 2.0 + 0.5, 0).
In the fragment shader, do just the opposite:
tangent = color.rgb * 2.0 - 1.0;
This allows us to correctly compute lighting for flatshaded primitives. Actually, the same system works for both flatshading and smoothshading. To ensure normals are correct for smoothshading, they should be normalized in the fragment shader. There is still a little problem: shading aliasing appears (e.g. in specular highlights) with this method. This is due to the limited-precision color components in a fixed-point pipeline. To prevent this, we need the GL_ARB_color_buffer_float extension and enable the floating-point pipeline with glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE).
Actually, what we would need is a way to specify that a varying variable should be interpolated according to the shading model. Unfortunately, this is not yet possible in the current version of the OpenGL Shading Language.
The second way is not using flatshading at all. The pfdBuilder constructs flatshaded geometry when all the normals of a primitive are the same. This is done in pfdBuildGSets() in pfdGeoBuilder.c. This is only done if the PFDGBLDR_COLLAPSE_ATTRS is 1. All of the pfdGeoBuilder options are also pfdBuilder options (with PFDBLDR_ prefix), except this one. To add it, we have to modify libpfdu and use our version statically in our application.
In pfdu.h, add
#define PFDBLDR_COLLAPSE_ATTRS 70
under the definition of PFDBLDR_PASS_REFERENCES
then change
#define PFDGBLDR_COLLAPSE_ATTRS 256
to
#define PFDGBLDR_COLLAPSE_ATTRS PFDBLDR_COLLAPSE_ATTRS
then, in pfdBuilder.c, add
pfdGeoBldrMode(b, PFDGBLDR_COLLAPSE_ATTRS,
(long)pfGet(CBldr->modes, PFDBLDR_COLLAPSE_ATTRS));
in pfdUpdateModes() and
pfSet(b->modes, PFDBLDR_COLLAPSE_ATTRS, (void *)1);
in SetupDefaultModes(). To disable construction of flatshaded geometry, we call pfdBldrMode(PFDBLDR_COLLAPSE_ATTRS, 0). This should be done in the flt loader, so we will also need to use a static version.
> Also, another problem with flt loader and Shaders is the fact that the
> loader seems to make some pre-computation on vertex colors and face
> materials : vertex colors seems to be multplicated by the diffuse color of
> the faces, and ambient and diffuse color of the face seem also to be
> affected by the color of the vertex. Although this doesn't affect classic
> OpenGL rendering, it is incompatible with our shader, which make a
> different use of this colors and need them untransformed.
Actually, I'm trying to prevent vertex colors to be specified if they are not used. I didn't really take a look at this but I think your problem is related. Take a look at the PFDBLDR_AUTO_COLORS option (used in pfdGeoBuilder.c (PFDGBLDR_AUTO_COLORS)).
Regards,
Hugues De Keyzer
de pinxi
This archive was generated by hypermail 2b29 : Thu Sep 08 2005 - 08:36:17 PDT