Passing values vert => frag without interpolation?


I have 8 light source positions in the vertex shader.
and I have to do “into tangent space”-transformation
on these vectors.

My first idea was to calculate the 8 light source tangent
space direction vectors in the vertex shader and then pass
them to the fragment shader with “out & in” (varyings).

But together with other varyings this will exceed
GL_MAX_VARYING_FLOATS on many cards.

Since I don’t need interpolation on the transformed positions
I wonder if there is an alternative to the limited varyings.
Something that comes without interpolation but more variable
capacity for passing values from vertex to fragment shader?

Help is really appreciated!

Since I don’t need interpolation on the transformed positions
I wonder if there is an alternative to the limited varyings.

No. Whether “Varyings” actually vary per-vertex is irrelevant; even if you turn off interpolation, it still takes up varying resources.

You can specify the flat variable qualifier. Then that variable will not be varying and shouldn’t count against your varying limit (but I haven’t tested that).

It might look something like this:
For vertex shader:
flat out vec3 Light_pos[8];

For fragment shader:
flat in vec3 Light_pos[8];

P.S. I composed this as Alfonse was posting his reply, and I didn’t see his post before posting mine. He may be right, I don’t know. According to the OpenGL 4.0 core spec (see section 2.11.7):

“The number of components (individual scalar numeric values) of varying and special variables that can be written by the vertex shader, whether or not a tessellation control, tessellation evaluation, or geometry shader is active, is given by the value of the implementation-dependent constant GL_MAX_VERTEX_OUTPUT_COMPONENTS.”

“Additionally, when linking a program containing only a vertex and fragment shader, there is a limit on the total number of components used as vertex shader outputs or fragment shader inputs. This limit is given by the value of the implementation-dependent constant GL_MAX_VARYING_COMPONENTS. Each varying or special variable component used as either a vertex shader output or fragment shader input count against this limit, except for the components of gl_Position.”

I think the spec is ambiguous in this regard. The first sentence of the last paragraph quoted doesn’t qualify variables are being varying or special, but the last sentence does. So which is it, really?

Ah cool thing somehow I missed this qualifier :o

Ok the only solution that comes to my mind is that I
pass the Normal, Tangent and Binormal (TBN Matrix)
as normal varying (without flat) to the fragment
shader and then calculate the tangent space light
positions in the fragment shader.

Maybe not beautiful but this way I bypass the varying
limitation =/

That works, but have you considered, instead of transforming the light positions into tangent space, transforming the tangent space normal into world space or eye space(whatever space the light positions are stored in) and doing the light there.

I must agree with the previous poster and suggest computing the TBN matrix for each vertex in some space (probably eye space) and passing this matrix as a vertex attribute. Is there a particular reason why you want the TBN to be different for each light? It would seem more natural and intuitive that the TBN depends on the surface geometry rather than the light source. Perhaps doing it with vertex attributes is even more consistent than recomputing per light source. In any event, there should be more than enough vertex attributes for you to try this approach if it suits your needs.



That’s a good call!

This way I save the transformations of the
8 light sources AND the vertex positions :slight_smile:

Hi! I already pass the tangent of the TBN Matrix as vertex
attribute and then calculate the Binormal with cross() from
the tangent and the vertex normal.

Actually, I believe it will still eat an interpolator, regardless what type of interpolation you request: smooth (the default), flat, or noperspective. Interpolator being the register space the value is passed in and the potential for the value to be interpolated.

Are you quite sure about that limit? Even a vs_1_1 device has 16 input registers, each of which holds 4 floats. You can pack your 8 positions into 6 of these and just go to work. Things might not be as bad as they seem, and you might be doing an awful lot of refactoring for no reason.

Even a vs_1_1 device has 16 input registers, each of which holds 4 floats.

Vertex shader inputs are not varyings. Varyings are vertex shader outputs.

Well as to vertex shader inputs (which is what you said), on both GTX285 and GTX480 (last-gen and this-gen), I see:


which I think is the max number of vtx attrib vec4s you can send into the vtx shader.

And as to interpolators (varyings, aka vtx shader outputs), again on GeForce GTX285 and GTX480 I see:


IIRC, this is the number of single-float interpolators you’ve got to play with, other than the vertex position.

(60+4)/4 = 16. So yes, the equivalent of 16 vec4’s here too.

I’m no expert on GL “Get” calls since they’re discouraged, but I believe those’re the right symbols. Somebody please correct me if not.

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