Projective texturing in OpenGL

Hey there!

Just getting going with OF at the mo - it’s top banana! I’m also trying to get my head around some Open GL stuff as I need some pretty specific graphical functionality for what I’m attempting to make. I’ve read various tutorials around the web on projective texturing, but none of them are elementary enough for me to take away working bits of code. Here’s what I’ve assembled so far. My texture is definitely loading as I can map it onto a quad using normal coords, but the projective stuff isn’t working. Any help much appreciated!

Cheers, sCam

  
  
void drawScene() {  
	  
	// clear canvas  
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
	  
	// enable and prime our loaded texture  
	glEnable(GL_TEXTURE_2D);  
	glBindTexture(GL_TEXTURE_2D, _textureId);  
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
	  
	// switch to texture mode for projective mapping  
	glMatrixMode (GL_TEXTURE);  
	glLoadIdentity ();  
	  
	// converts -1 to 1 into 0 to 1   
	glTranslatef (1.0f, 1.0f, 1.0f);  
	glScalef (0.5f, 0.5f, 0.5f);  
	  
	// our projectors setup and position  
	gluPerspective (90.0f, 1.0f, 0.1f, 1.0f);  
	gluLookAt(0.0f, 0.0f, -5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);  
	  
	// generate the texture stuff  
	glEnable (GL_TEXTURE_GEN_S);  
	glEnable (GL_TEXTURE_GEN_T);  
	glEnable (GL_TEXTURE_GEN_R);  
	glEnable (GL_TEXTURE_GEN_Q);  
	glTexGenf (GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);  
	glTexGenf (GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);  
	glTexGenf (GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);  
	glTexGenf (GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);  
	  
	// goto our plane location and draw  
	glMatrixMode(GL_MODELVIEW);  
	glLoadIdentity();  
	glTranslatef(0.0f, 0.0f, -5.0f);  
	  
	glBegin(GL_QUADS);  
		glNormal3f(0.0f, 0.0f, 1.0f);  
		glVertex3f(-1.0f, -1.0f, 0.0f);  
		glVertex3f(1.0f, -1.0f, 0.0f);  
		glVertex3f(1.0f, 1.0f, 0.0f);  
		glVertex3f(-1.0f, 1.0f, 0.0f);  
	glEnd();  
	  
	glutSwapBuffers();  
  
}  
  

Hey, I’m playing with getting this working in straight openGL but IMO it’s way easier to get working using a shader:

vertex

  
  
varying vec4 ProjTexCoord;  
void main()  
{  
	mat4 textureMat;  
	gl_Position = ftransform();  
  
	gl_TexCoord[0] = gl_MultiTexCoord0;  
	textureMat=mat4(0.5,0.0,0.0,0.0,0.0,0.5,0.0,0.0,0.0,0.0,0.5,0.0,0.5,0.5,0.5,1.0);  
  
	ProjTexCoord=(textureMat * gl_ModelViewProjectionMatrix)*gl_Vertex;  
}  
  

frag

  
  
  
uniform sampler2DRect tex0;  
uniform sampler2DRect tex1;  
varying vec4 ProjTexCoord;  
  
void main()  
{  
	vec4 color;  
	vec4 colProj;  
  
	color = texture2D(tex0, gl_TexCoord[0].xy);  
	colProj = texture2DRectProj(tex1, ProjTexCoord);  
	color = color * colProj;  
  
	gl_FragColor = color;  
}   

try using them with the ofShader. I’ll see if I can get this working with just the OGL calls.

Actually, I’m going to take that back. These work in Shader Builder, which I should probably stop using in OF apps b/c of the difficulty of getting multiTexturing working but I can’t get them working in OF. Using the following:

  
  
#include "testApp.h"  
  
void testApp::setup(){  
	  
	shader.setup("proj.vs", "proj.fs");  
	  
	//ofDisableArbTex();  
	  
	bikers.loadImage("images/bikers.jpg");  
	tdf.loadImage("images/tdf_1972_poster.jpg");	  
}  
  
void testApp::update(){}  
  
void testApp::draw(){	  
	  
	ofBackground(255, 255, 255);  
	shader.begin();  
	shader.setUniformTexture("tex0", bikers.getTextureReference(), 1);  
	shader.setUniformTexture("tex1", tdf.getTextureReference(), 2);  
	  
	glBegin(GL_QUADS);  
		glVertex3f(0, 0, 1);  
		glVertex3f(1024, 0, 1);  
		glVertex3f(1024, 768, 1);  
		glVertex3f(0, 768, 1);  
	glEnd();  
	shader.end();  
	  
}  
  

with these:

  
varying vec4 ProjTexCoord;  
void main()  
{  
   mat4 textureMat;  
   gl_Position = ftransform();  
  
   gl_TexCoord[0] = gl_MultiTexCoord0;  
  
	/*textureMat=mat4( 0.5, 0.0, 0.0, 0.0,  
				   0.0, 0.5, 0.0, 0.0,  
				   0.0, 0.0, 0.5, 0.0,  
				   0.5, 0.5, 0.5, 1.0);*/  
	textureMat=mat4( 512, 0.0, 0.0, 0.0,  
				   0.0, 512, 0.0, 0.0,  
				   0.0, 0.0, 512, 0.0,  
				   256, 256, 256, 1);  
  
   ProjTexCoord = (textureMat * gl_ModelViewProjectionMatrix) * gl_Vertex;  
}  

and

  
  
uniform sampler2DRect tex0;  
uniform sampler2DRect tex1;  
/*uniform sampler2D tex1;  
uniform sampler2D tex0;*/  
varying vec4 ProjTexCoord;  
  
void main()  
{  
   vec4 color;  
   vec4 colProj;  
  
   color = texture2DRect(tex0, gl_TexCoord[0].st);  
   colProj = texture2DRectProj(tex1, ProjTexCoord);  
   color = color * colProj;  
  
   /*color = texture2D(tex0, gl_TexCoord[0].xy);  
   colProj = texture2DProj(tex1, ProjTexCoord);  
   color = color * colProj;*/  
  
   gl_FragColor = color;  
}  

both of which were mangled a bit to get them working with sampler2DRect rather than sampler2D, I get the attached image. I’ll report back w/any progress, sorry to be all “I fixed it for ya”. I thought that the setUniformTexture() would do the trick, but it doesn’t. Whoops.

![](http://forum.openframeworks.cc/uploads/default/977/Screen shot 2011-02-15 at 8.23.44 PM.png)

Hey!

Thanks so much for taking a look! If the shader approach is being a bit of a trickster, any idea how to get the ‘fixed pipeline’ version workin?

Cheers, sCam

Actually, I’m still trying to get the shader stuff tracked down, sorry. I’ll get back to the fixed pipeline shortly. Have you looked at this http://www.sgi.com/products/software/op-…-/projtex.c ?

Back to the shader, in case anyone else is following this. I’ve been working with the shader, trying to get this working. I stripped out the ofShader stuff to see if I can get pinpoint the problem a little better:

  
void testApp::setup(){  
	  
	shader.setup("proj.vs", "proj.fs");  
  
	everyone.setImageType(OF_IMAGE_COLOR);  
	tdf.setImageType(OF_IMAGE_COLOR);  
	  
	everyone.loadImage("images/everyonehasaplan.jpg");  
	tdf.loadImage("images/tdf_1972_poster.jpg");  
	  
	GLuint t1 = glGetUniformLocation(shader.getProgram(), "tex0");  
    GLuint t2 = glGetUniformLocation(shader.getProgram(), "tex1");  
	  
	GLint one = 1;  
	GLint zero = 0;  
	// should be ARB, I think?  
      glUniform1iARB(t1, zero);  
    glUniform1iARB(t2, one);  
	  
	glUseProgram(shader.getProgram());  
	  
}  
  
void testApp::draw(){	  
	  
	  
	glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );  
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );  
	  
// should be arb?  
    glActiveTextureARB(GL_TEXTURE0);  
	glEnable(GL_TEXTURE_2D);  
    glBindTexture((int) tdf.getTextureReference().getTextureData().textureTarget, (int) tdf.getTextureReference().getTextureData().textureID);  
	  
	glActiveTextureARB(GL_TEXTURE1);  
	glEnable(GL_TEXTURE_2D);  
    glBindTexture((int) everyone.getTextureReference().getTextureData().textureTarget, (int) everyone.getTextureReference().getTextureData().textureID);  
	  
	glBegin(GL_QUADS);  
		glTexCoord2f(0, 0);  
		glVertex3f(0, 0, 0);  
		glTexCoord2f(everyone.getWidth(), 0);  
		glVertex3f(1024, 0, 0);  
		glTexCoord2f(everyone.getWidth(), everyone.getHeight());  
		glVertex3f(1024, 768, 0);  
		glTexCoord2f(0, everyone.getHeight());  
		glVertex3f(0, 768, 0);  
	glEnd();  
  
}  

This does the projective mapping, but loads only the first image, not the second, if you see the attached img. Anyone have an idea?

![](http://forum.openframeworks.cc/uploads/default/979/Screen shot 2011-02-16 at 11.16.36 AM.png)

Hey!

Yeah I’ve seen that link - I pulled some of my elements from there but to be honest there’s a lot going on in that code and I’m too much of a n00b to know which bits are relevant.

Thanks for your continued efforts!

Cheers, sCam

Alright, using an FBO, it works. I don’t know why. Seems like a bug to me :confused:

  
void testApp::setup(){  
	  
	shader.setup("proj.vs", "proj.fs");  
	  
	//ofDisableArbTex();  
	  
	everyone.setImageType(OF_IMAGE_COLOR);  
	tdf.setImageType(OF_IMAGE_COLOR);  
	  
	first.setup(512, 512, GL_RGBA);  
	second.setup(512, 512, GL_RGBA);  
	third.setup(1024, 768, GL_RGBA);  
	  
	everyone.loadImage("images/everyonehasaplan.jpg");  
	tdf.loadImage("images/tdf_1972_poster.jpg");  
	  
  
	shader.begin();  
	shader.setUniform1i("tex0", 0);  
	shader.setUniform1i("tex1", 1);  
	shader.end();  
	hasDrawnTex = false;  
	  
}  
  
  
void testApp::draw(){	  
	  
	ofClear(1.f,1.f,1.f,1.f);  
	  
	if( !hasDrawnTex )  
	{  
		first.begin();  
		everyone.draw(0, 0, 0);  
		first.end();  
		second.begin();  
		tdf.draw(0, 0, 0);  
		second.end();  
		hasDrawnTex = true;  
	}  
	  
	  
	//third.begin();  
	  
	glActiveTexture(GL_TEXTURE0);  
	first.getTexture(0).bind();  
	  
	//blurred  
	glActiveTexture(GL_TEXTURE1);  
	second.getTexture(0).bind();  
	  
	shader.begin();  
	  
	glBegin(GL_QUADS);  
		glTexCoord2f(0, 0);  
		glVertex3f(100, 100, 0);  
		glTexCoord2f(everyone.getWidth(), 0);  
		glVertex3f(612, 100, 0);  
		glTexCoord2f(everyone.getWidth(), everyone.getHeight());  
		glVertex3f(612, 486, 0);  
		glTexCoord2f(0, everyone.getHeight());  
		glVertex3f(100, 486, 0);  
	glEnd();  
	  
	shader.end();  
	  
	glActiveTexture(GL_TEXTURE1);  
	second.getTexture(0).unbind();  
	  
	glActiveTexture(GL_TEXTURE0);  
	first.getTexture(0).unbind();  
  
}  

007 project is attached (in XCode). Don’t be thrown off by the poor naming of the project file, it’s late and I’m too lazy to change it :slight_smile:

imageLoaderExample.zip

Thanks very much for your perseverance! I’ll DL the files and take a look!

Cheers, sCam

First up thanks again so much for your help :slight_smile: I hope you don’t mind me asking a few more questions just to get my head around this!

OK, so I’ve compiled the example, which works fine. Just starting to deconstruct it a bit…I’m not 100% sure exactly what’s going on. If I disable the second image, just leaving the “everyone” image (like the text BTW!) and I look at the rendered result I get the attached file.

How come this image is being rendered twice onto the quad?

Cheers, sCam

I’m not sure why that’s going on. My *guess* is that the shader is grabbing the first image to project since a 2nd one isn’t bound. By disable do you mean you’re not binding it or drawing it into the FBO? Might be a little bug somewhere too…

Hey!

Yes it was exactly as you say - cause I’d just commented out the code in the app and not the shader. God I’m like a bull in a china shop!

Just one more question then I promise I’ll leave you alone for a bit! I presume at the moment this is projectively mapping from the viewer’s position. What I’m actually trying to get at is to be able to shine the texture onto some geometry from one ‘view’ then actually look it from another. Can you give me some idea of how I would go about doing that?

Again, many thanks!

Cheers, sCam