Efficient vertex program texture projection?

Right now I’m using the fixed-function pipeline to do my projective texturing (planar)…
I’m using the following to setup my texture matrix and it works well.

      glMatrixMode     (GL_TEXTURE);
        /*
        glLoadIdentity ();
        glTranslatef   (0.5f, 0.5f, 0.0f);
        glScalef       (0.5f, 0.5f, 1.0f);
        */
        glLoadMatrixf  (mEnvBase.m); /* Result of the above logic is a constant matrix... */
        glMultMatrixf  (mEnvProj.m);
        glMultMatrixf  (mEnvModel.m);
      glMatrixMode     (GL_MODELVIEW);

My question is, what’s the most efficient approach to doing the same thing
in a vertex program?

Should I just keep the code as it is and multiply the texture coordinates by
the appropriate texture matrix in the vertex program? I don’t want to pass
the vertex program the projection*modelview matrix (see below) for performance
reasons.

Cg provides a special projective texture lookup intrinsic for fragment programs,
that as I understand it, divides the texture matrix by its last component (equiv.
to the glTranslate/glScale logic above?). I’m assuming there’s some advantage to
doing it in a fragment program that I’m just too stupid to see? It seems to me
that all of the work could be done per-vertex and you’d save a few GPU cycles
per-fragment… Am I missing something here?

I also noticed (to my surprise) that pre-multiplying the Env Projection /
Modelview matrices on the CPU every time the projector’s view changes (I have
a latency of 4+ frames, to keep the pixel buffer from eating too much fillrate)
is actually 10-15% slower than doing the projection and modelview mults EVERY
FRAME w/ glMultMatrixf.

The following, which logically seems like an optimization turns out slower than
the original code:

  [Update Pixel Buffer (once every 4+ frames)]
  --------------------------------------------
  ...
    const l3dMatrix& mEnvProj  = world.camera.projection ();
    const l3dMatrix& mEnvModel = world.camera.modelview  ();

    mEnvProjView = mEnvProj * mEnvModel;
  ...


  [Project Pixel Buffer's Texture (every frame)]
  ----------------------------------------------
  ...
      glLoadMatrixf  (mEnvBase.m);
      glMultMatrixf  (mEnvProjView.m);
    glMatrixMode     (GL_MODELVIEW);
  ...

Lesson learned here:

  • Don’t assume fewer operations per-frame/update are always “better” :stuck_out_tongue:

(The driver can take advantage of SIMD/MMX instruction sets and other optimizations
that unless you have a REALLY nice math library, could prove orders of magnitude
faster than your own code…)

Figured I’d share that little bit since it really surprised me :slight_smile:

You could try the following:

automatic texture coord generation code (only has to be set when mEnvProj changes, which should not be too often.

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
	
glActiveTextureARB(GL_TEXTURE0_ARB);
	
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);

mEnv=mEnvBase*mEnvProj;
  
glTexGenf(GL_S, GL_EYE_PLANE, mEnv.m[0], mEnv.m[4], mEnv.m[8], mEnv.m[12]);
glTexGenf(GL_T, GL_EYE_PLANE, mEnv.m[1], mEnv.m[5], mEnv.m[9], mEnv.m[13]);
glTexGenf(GL_R, GL_EYE_PLANE, mEnv.m[2], mEnv.m[6], mEnv.m[10], mEnv.m[14]);
glTexGenf(GL_Q, GL_EYE_PLANE, mEnv.m[3], mEnv.m[7], mEnv.m[11], mEnv.m[15]);
  
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_GEN_Q);

in vertex program add the line

MOV result.texcoord[0], vertex.texcoord[0];

Greetz,

Nico

Uh, isn’t tex gen mode disabled when using vertex programs?

In anycase you don’t need it since you can assign the vertex values to the texcoords (after modelview transform for eye space texgen) which is a very efficient texgen for something like texture projection, then you can multiply the texture coordinate by your texture matrix.