Hey folks!
I’m struggling with some of the matrix math for a projective texture shader (https://en.wikipedia.org/wiki/Projective_texture_mapping).
The image is showing up on the plane, but not in the position or with the skew that I was expecting. I’m working from an example in OpenGL 4.0 Shading Language Cookbook that doesn’t appear to be available online. It crossed my mind that the issue could be author’s use of glm::lookAt vs ofMatrix4x4::makeLookAtViewMatrix, or the fact that I’m using an ARB texture, but switching to a square texture didn’t fix it.
Here’s my OF code. Would be super grateful for any direction/corrections.
//--------------------------------------------------------------
void ofApp::setup(){
ofEnableLighting();
ofEnableDepthTest();
texture.load("Rhythmus.jpg");
texture.getTexture().setTextureMinMagFilter(GL_LINEAR, GL_LINEAR);
texture.getTexture().setTextureWrap(GL_CLAMP_TO_BORDER_ARB, GL_CLAMP_TO_BORDER_ARB);
textureProjectionShader.load("TextureProjection");
plane.set(20000,20000,2,2);
}
//--------------------------------------------------------------
void ofApp::draw(){
ofBackground(0);
camera.setFarClip(1000);
camera.setPosition(0,0,800);
camera.lookAt(ofVec3f());
camera.begin();
// projector coordinates
ofVec3f projectorPos = ofVec3f( 0, 0, 400 );
ofVec3f projectorLookAt = ofVec3f( sin(ofGetElapsedTimef()) * 100, cos(ofGetElapsedTimef())*100, 0);
ofVec3f projectorUp = ofVec3f( 0, 1, 0);
// projector's view matrix
ofMatrix4x4 projectionView;// = ofMatrix4x4::newLookAtMatrix(projectorPos, projectorLookAt, projectorUp);
projectionView.makeLookAtViewMatrix(projectorPos, projectorLookAt, projectorUp);
// projector's perspective materix
float aspect = float(texture.getWidth()) / texture.getHeight();
ofMatrix4x4 projectionProj = ofMatrix4x4::newPerspectiveMatrix(60, 1.0/aspect, 1.0, 2000.0);
// translate into texture space (0.0 - 1.0)
ofMatrix4x4 projectionTrans;
projectionTrans.makeTranslationMatrix(ofVec3f(0.5, 0.5, 0.5));
projectionTrans.scale(ofVec3f(0.5, 0.5, 0.5));
// create our projector matrices
ofMatrix4x4 projectorMat = projectionTrans * projectionProj * projectionView;
// set our plane's material properties
ofFloatColor ambientMat = ofFloatColor(0.1,0.1,0.1,1.0);
ofFloatColor diffuseMat = ofFloatColor(0.5,0.5,0.5,1.0);
ofFloatColor specularMat = ofFloatColor(0.0,0.0,0.0,1.0);
float shininessMat = 0;
// finally, our model matrix
ofMatrix4x4 modelMatrix = ofMatrix4x4::newIdentityMatrix();
textureProjectionShader.begin();
textureProjectionShader.setUniformMatrix4f("modelMatrix", modelMatrix);
textureProjectionShader.setUniformMatrix4f("projectorMatrix", projectorMat);
textureProjectionShader.setUniformTexture("projectorTex", texture, 0);
textureProjectionShader.setUniform3fv("material.ka", &ambientMat.r);
textureProjectionShader.setUniform3fv("material.kd", &diffuseMat.r);
textureProjectionShader.setUniform3fv("material.ks", &specularMat.r);
textureProjectionShader.setUniform1f("material.shininess", shininessMat);
textureProjectionShader.setUniform3f("light.intensity", 1.0f, 1.0f, 1.0f);
textureProjectionShader.setUniform3f("light.position", 0.0, 0.0, 30.0);
plane.draw();
textureProjectionShader.end();
// debugin'
ofSetColor(255);
ofDrawSphere(projectorPos, 5);
ofDrawSphere(projectorLookAt, 2);
ofDrawLine(projectorPos, projectorLookAt);
camera.end();
// preview the texture
float w = 60;
float h = 60 * 1.0/aspect;
texture.draw(10, 10, w, h);
}
My vertex shader
#version 150
uniform mat4 projectorMatrix;
uniform mat4 modelMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 textureMatrix;
uniform mat4 normalMatrix;
uniform mat4 modelViewProjectionMatrix;
in vec4 position;
in vec2 texcoord;
in vec4 color;
in vec3 normal;
out vec3 eyeNormal;
out vec4 eyePosition;
out vec4 projTextCoord;
void main(){
eyeNormal = normalize( normalMatrix * vec4(normal, 1.0) ).xyz;
eyePosition = modelViewMatrix * position;
projTextCoord = projectorMatrix * modelMatrix * position;
gl_Position = modelViewProjectionMatrix * position;
}
And finally the fragment shader:
#version 150
uniform sampler2DRect projectorTex;
struct MaterialInfo {
vec3 ka;
vec3 kd;
vec3 ks;
float shininess;
};
uniform MaterialInfo material;
struct LightInfo {
vec3 intensity;
vec4 position;
};
uniform LightInfo light;
in vec3 eyeNormal;
in vec4 eyePosition;
in vec4 projTextCoord;
out vec4 fragColor;
vec3 phongModel( vec3 pos, vec3 norm ){
vec3 s = normalize(vec3(light.position)-pos);
vec3 v = normalize(-pos.xyz);
vec3 r = reflect( -s, norm);
vec3 ambient = light.intensity * material.ka;
float sDotN = max( dot(s, norm), 0.0 );
vec3 diffuse = light.intensity * material.kd * sDotN;
vec3 spec = vec3(0.0, 0.0, 0.0);
if( sDotN > 0.0 ){
spec = light.intensity * material.ks * pow(max(dot(r,v),0.0), material.shininess);
}
return ambient + diffuse + spec;
}
void main(){
vec3 color = phongModel( vec3( eyePosition), eyeNormal);
vec4 projTexColor = vec4( 0.0, 0.0, 0.0, 0.0);
if( projTextCoord.z > 0.0 ){
projTexColor = textureProj( projectorTex, projTextCoord );
}
fragColor = vec4(color, 1.0) + projTexColor;
}
Also attaching the source code (and the book example).
TextureProjection.zip (93.7 KB)