# Projective Textures

Hi all

First as I’m new let me say hi to you all. I’ve been coding in OpenGL on and off for about a year now and am currently programming a game engine.

I’ve been unable as of yet to implement or even understand the first thing about projective textures. I have read numerous resources about them and even have a book which covers them. None I can understand it from.

As it appears (and please correct me if I’m wrong), there is parallel and perspective texture projection. I am pretty sure how each look.

After that, the matrix stuff throws me off and I can’t follow it. Also, there is this Q texture coordinate or something. All of this confuses me quite a lot!

Would it be possible for someone to outline steps (possibly with example code)? I tend to learn best looking a code (or pseudo code) than with theory.

Thank you,
Lprogster

I assume you have read http://developer.nvidia.com/object/Projective_Texture_Mapping.html

Are you using shaders or fixed function?

In a nutshell, if you understand how model-view-project transforms a vertex onto the screen - you understand how this gets projected into screen coordinates of (-1,-1) to (1,1).

What the 1/2 type matrix in the above article is doing is taking it from this (-1,-1) - (1,1) space into (0,0) - (1,1) space.

If this is too complex for you to under stand, I can should you how to do it with shaders without this additional matrix step. (you need to know shaders first however)

I now understand what the matrix does. Am I right in thinking this does the same thing?:

glTranslatef(.5f, .5f, 0.f);
glScalef(.5f, .5f, 1.f);

I don’t actually understand what to do to get the projection into screen coordinates. I believe it involves some matrix multiplications from 2 or 3 matrixes. One of which is that “1/2 type” matrix I think.

I think this is beginning to come together now.

EDIT: I don’t really want to use shaders, if possible.

Am I right or totally wrong? I could well be way out here.

OK, if you want to use fixed function, you have to know I am a little rusty at it.

The first step I think we should do is ignore all that matrix stuff and focus getting the texture coordinate generation working correctly.

The result of this first step should be a tiled texture projected onto the scene from the camera view. (Tiled two times in x and y)

// Activate the texture stage you want projected texturing on
glActiveTexture(GL_TEXTURE0);

glMatrixMode(GL_TEXTURE);

// Do the operations you did to setup GL_PROJECTION matrix (use glGet then a glMultMatrix if lazy)

// Do the operations you supplied in GL_MODELVIEW matrix mode (use glGet then a glMultMatrix if lazy)

glMatrixMode(GL_MODELVIEW); // Reset matrix mode to modelview

// Set up texture coordinate generation mode
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);

glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);

// Draw objects

// Disable projective texturing mode
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glMatrixMode(GL_TEXTURE);
glMatrixMode(GL_MODELVIEW);

Thanks for the reply. I understand what to do up until the bit:

// Draw objects

at which point I’m wondering if you mean redraw the scene or draw another object. Could you clarify please?

Thank you,
Lprogster

I mean to draw the objects in the scene you want the texture projected on. This will involve binding your projected texture (and any other textures) enabling vertex buffers and issuing draw calls etc.

Note that if you have to draw multiple objects, you will have to re-do the texture matrix for each object (with each objects’ model view matrix). In later steps I’ll show you how you can do it once then render all objects.

Feel free to post screen shots or code if it does not work.

OK, so if I wanted to project a texture onto the terrain would I draw the terrain first and then again where “// Draw objects” is? I’m not quite sure how the order of things go.

I’ll post a screenshot next post if I can’t figure it out.

Thank you,
Lster

Or do I draw it only once, where the “// Draw objects” is? I tried this only drawing the terrain where “// Draw objects” is and it kind of works. I have two active texture units and one is set like your code showed (for the projection?), the other is used for the terrain texture.

The texture stretches weirdly over the terrain now. Is this right; should I post a screenshot?

Thank you,
Lster

I have no idea what “weirdly” would look like so you should post a screen shot.

one thing that helps is drawing of the frustum onscreen as a wireframe

glMultMatrixf( inverse_modelview_matrix );
glMultMatrixf( inverse_projection_matrix );
draw the box from coordinates (-1,-1,-1) -> (1,1,1)

Is a screenshot of the “weird” texturing. It kind of stretches but only in one dimension (I’m not sure whether it’s the X of Z dimension). I can post others if necessary.

Yes, that screen shot is very wrong.
If you can post a runnable exe I’ll run it through a debugger (I don’t require source) otherwise, I suggest you might want to have a look at the matrix settings.

I have it doing what you want, I think! But I was really just trying out random stuff. When you said:

glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);

did you really mean?:

… GL_EYE_LINEAR …

That seems to give me the effect you said but I have no idea whether this is just luck. The texture kind of stretches over the terrain depending on where the camera is pointing. It really does look realistic!

Is this correct or a fluke?

Thank you,
Lprogster

If you use EYE_LINEAR the texture coordinate generation is dependent on the value of the modelview matrix when the function is called. If you don’t want the texture projection to change I think you’re better off using OBJECT_LINEAR.

Object linear texture coordinate generation is very easy. All you need is a 4x4 matrix describing the transform, let’s call this TG.
Every vertex V, in object space, gets multiplied by this matrix and generates.

texcoord = TG*V;

You can set the values of TG (row major) by calling:

glActiveTextureARB(GL_TEXTURE0);

glTexGenfv(GL_S, GL_OBJECT_PLANE, &TG[0]);

glTexGenfv(GL_T, GL_OBJECT_PLANE, &TG[4]);

glTexGenfv(GL_R, GL_OBJECT_PLANE, &TG[8]);

glTexGenfv(GL_Q, GL_OBJECT_PLANE, &TG[12]);

glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);

glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);

glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);

glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);

glEnable(GL_TEXTURE_GEN_S);

glEnable(GL_TEXTURE_GEN_T);

glEnable(GL_TEXTURE_GEN_R);

glEnable(GL_TEXTURE_GEN_Q);

The default state for object linear texture coordinate generation is:

float TG[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

N.

OK, I even understand that kind of but when I try that, I don’t get any texturing on the terrain at all. Any ideas; and how do I calculate TG?

Thank you,
Lprogster

Well, that’s a rather vague question. It depends on how you want your texture to be projected. Is it an orthographic projection from above, a perspective projection? Are your vertices defined in the xy plane and rotated by the modelview matrix or are they in xz plane already…

e.g. if your vertices are in the xy plane with the z offset as height with
minimum of all x = 0
maximum of all x = 1000
minimum of all y = 0
maximum of all y = 2000

then the TG matrix will probably be something like

|1/1000    0    0    0|
|   0   1/2000  0    0|
|   0      0    0    0|
|   0      0    0    0|

This will map the [0…1000]x[0…2000] range of the vertices to the [0…1]x[0…1] range of texture coordinates.

N.

If GL_EYE_LINEAR seems to “work” I suggest you re-look at the matrix code (or post it here) as GL_OBJECT_LINEAR should be what you want.

Hi again.

Well basically all I do in transforming the texture is multiply it with the projection and modelview matrices using glGet and then glMultMatrix. I’m wondering: do I have to transpose the matrices before multiplying them? If I do, how can I do that?

Thank you,
Lprogster

The only thing I can think of is if you have not setup the modelview matrix properly before you do the glGet.

(You could also try and switch the order of the multiplications)