Cg and updating a state matrix parameter

I’ve got Cg shaders that I want to apply to large numbers of objects, each in a different location. I’ve got the geometry in a vertex array and can paint it as much as I like (without shaders) by drawing it with different modelview matrices.

If I bind & enable the Cg shader before drawing all the objects, only the first one appears. My vertex program gets the modelview matrix (and inverse transpose) through cgGLSetStateMatrixParameter and it doesn’t seem to be shadowing the GL state correctly.

It doesn’t even work if I re-set the state matrix parameter after each update to the modelview matrix. Not even if I glFlush() between each object. It only renders the other objects if I disable & re-enable the Cg profile and rebind the program after every state matrix change.

Any way I can avoid rebinding the whole shader for every object? As far as I can tell, it means downloading all the parameters (including unchanged ones) into static memory again and is definitely slow.

I’m using fglrx 8.10.19 on linux, Cg 1.3.0501.0700 using profile ARBVP1. Some glGets:
Renderer: RADEON 9600 Generic
Version: 1.3.4893 (X4.3.0-8.10.19)

Cg 1.4 is a bit better for non-nvidia cards (at least supposed to). Also most Cg related stuff probably is best asked at www.shadertech.com forums.

about the problem I use following way for the matrices

main(…, uniform float4x4 ModelViewProj : state.matrix.mvp, …)

and it worked well on cg1.3 and radeon, too.

OK, thanks. I’ll give 1.4 a go and wander over to shadertech.

I tried the glstate.matrix.* thing and somehow all my lighting gets destroyed if I access any of those glstate matrices. Specular become an on/off thing, lighting up the whole side of the object. That’s even if the ONLY glstate matrix I touch does not have any contribution to lighting - invtrans.modelview[0], which I use only to transform the point to clipspace.

thanks for your help.

Originally posted by polyglot:
I tried the glstate.matrix.* thing and somehow all my lighting gets destroyed if I access any of those glstate matrices.
I’ve used glstate.matrix.* on an ATI card with arbvp1/arbfp1 and shader lighting and had no problems.

… That’s even if the ONLY glstate matrix I touch does not have any contribution to lighting - invtrans.modelview[0], which I use only to transform the point to clipspace.
Why would use use glstate.matrix.invtrans.modelview[0] to transform points to clip space. Do you mean glstate.matrix.mvp?

yeah, that was a dumb/wrong explanation; my bad. What I was trying to say was that if I used any one of the glstate matrices, it would break things not even related to or dependent on that matrix.

This is the vertex program:

/*
        Tex0: passthru 
        Tex1: reflection map

        color0: diffuse
        color1: specular
*/

#if 0
#define MVP glstate.matrix.mvp
#define MV glstate.matrix.modelview[0]
#define ITMV glstate.matrix.invtrans.modelview[0]
#else
#define MVP modelview_proj
#define MV modelview
#define ITMV modelviewIT
#endif

void main(in float4 pos : POSITION,
          in float4 norm : NORMAL,
          in float3 tex0 : TEXCOORD0,
          out float4 Opos : POSITION,
          out float3 Ocol0 : COLOR0,
          out float3 Ocol1 : COLOR1,
          out float3 Otex0 : TEXCOORD0,
          out float3 Otex1 : TEXCOORD1,

          uniform float4x4 modelview,
          uniform float4x4 modelview_proj,
          uniform float4x4 modelviewIT,
          uniform float4 lightvec,                      // direction TO light, in EYE space
          uniform float3 light_d,
          uniform float3 light_s                // lighting colours
        )
{
        // clip-space position
        Opos = mul(MVP, pos);

        // transform normal to view space
        float3 normal=normalize(mul(ITMV, norm).xyz);

        // pass-thru first texcoord
        Otex0 = tex0;

        // bad approx of vector to eye
        // float3 eye=float3(0.0, 0.0, 1.0);

        // actual eye-vector (from eye to vertex)
        float3 eye=normalize(mul(MV, pos));

        // reflection map for 2nd texcoord
        Otex1 = reflect(eye, normal);
//      Otex1 = normalize(2*normal+eye);

        // half-angle vector
        float3 halfa=normalize(lightvec - eye);

        // brightnesses
        float diffuse=dot(normal, lightvec);
        float specular=dot(normal, halfa);

        // y = diffuse, z = specular (1-facedness + power)
        float4 lighting=lit(diffuse, specular, 32);
        Ocol0.rgb = lighting.y * light_d;

        // specular colour
        Ocol1 = lighting.z * light_s;

        // debugging purposes...
        Ocol1 = Otex1;
}

Anyway. Using explicitly-passed matrices, it works properly. Using the glstate matrices, I discovered that the reflect() was returning its first argument instead of the reflection, also that the lit operation was returning bogus results. The glstate matrices seem to have the correct value.

See the debugging thing at the end - when working, the specular colour will be the reflection vector. When using the glstate stuff, it still contains the eye vector.

PS: shadertech forums seem to be down, so I figured I’d bother you guys instead :wink: And I’ve been too slack to install Cg 1.4 yet, but will hopefully soon.

there might also be a bug in the radeon arb vprog parser, at least it exists for me. As Cg compiles to the ARB_program extension it might affect the result.

doing
PARAM blah = {0,1,2,3}
is not liked by ATI vertex programs, Cg however might use it a lot to combine constants.

as workaround I pass constants with parameters in Cg as well. which will turn it into another local parameter, and that works for ATI, too.

Resolved now - it was a driver bug. Upgraded to fglrx 8.19.10 and now it works using the glstate parameters and no explicit passing.

It also now permits partial downloads of uniform data without having to rebind the whole vertex program.

Anyway, thanks for your help.