Hi!
I think, I see what you would like to do. You want to render the texture coordinates into a texture to compute the derivatives with respect to the screen yourself, right?
So first, you need an FBO. An FBO (frame buffer object) is a container that describes where the output of your shader goes to. It can have one or more color textures and one depth texture.
This is some initialization code:
// --- Some global variables ---
// Texture Ids and Framebuffer Object Ids
GLuint textureId = 0; // color texture to render into
GLuint depthTextureId = 0; // depth texture used for depth testing
GLuint myFBO = 0; // FBO containing the two textures above.
// --- in the init function ---
// Create texture
glGenTextures (1, &textureId);
glBindTexture (GL_TEXTURE_2D, textureId);
glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
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_WRAP_S, GL_CLAMP);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
// Create depth buffer
glGenTextures (1, &depthTextureId);
glBindTexture (GL_TEXTURE_2D, depthTextureId);
glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Create FBO and assign textures
glGenFramebuffers (1, &myFBO);
glBindFramebuffer (GL_FRAMEBUFFER, myFBO);
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0);
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTextureId, 0);
// check framebuffer status --> everything fine?
GLenum status = glCheckFramebufferStatus (GL_FRAMEBUFFER);
switch (status)
{
case GL_FRAMEBUFFER_COMPLETE:
cout << "FBO complete" << endl;
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
cout << "FBO configuration unsupported" << endl;
return 1;
default:
cout << "FBO programmer error" << endl;
return 1;
}
glBindFramebuffer (GL_FRAMEBUFFER, 0);
return 0;
This code creates and FBO, assigns a color texture (RGBA, 8 bit per component) and a depth texture and checks whether the initialization was successful.
Now, you want to render into the texture, which goes like this:
glBindFramebuffer (GL_FRAMEBUFFER, myFBO); // activate fbo -> from now on, we render to the FBO
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the content of fhe FBO
// ... rendering code
glBindFramebuffer (GL_FRAMEBUFFER, 0); // deactivate fbo -> from now on, we render to the backbuffer
How to proceed depends a little on what you're trying to do.
If you want to implement your effect as some sort of post effect, you'd render a quad covering the entire screen, which yields one pixel shader execution per pixel.
Rendering the quad:
void drawScreenFillingQuad()
{
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glBegin(GL_QUADS);
{
glTexCoord2f(0,0);
glVertex2f(-1,-1);
glTexCoord2f(1,0);
glVertex2f( 1,-1);
glTexCoord2f(1,1);
glVertex2f(1,1);
glTexCoord2f(0,1);
glVertex2f( -1,1);
}
glEnd();
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
}In the shader, you can take the texture coordinate and directly read from the texture. (Make sure you bind the color texture of your FBO (textureID) as a texture!)
Vertex Shader:
void main()
{
gl_Position = ftransform();
gl_TexCoord[0] = gl_MultiTexCoord0;
}Fragment Shader:
uniform sampler2D texture;
void main()
{
gl_FragColor = texture2D(texture,gl_TexCoord[0].st); // just read the texture and display it
}If you don't draw a full screen quad, but the real scene geometry instead, we need to figure out the texture coordinate for fetching from the background texture ourselves.
For this, you'd have to pass the clipping space position from the vertex shader to the fragment shader.
Vertex Shader:
varying vec4 clipPos;
void main()
{
gl_Position = ftransform();
clipPos = gl_Position;
}And in the fragment shader we scale the clipping space position (which is in [-1,1]) to the texture coordinate domain [0,1].
Fragment Shader:
uniform sampler2D texture;
varying vec4 clipPos;
void main()
{
// project to cartesian coordinates and scale from [-1,1] to [0,1].
vec2 texCoord = clipPos.xy / clipPos.w * 0.5 + vec2(0.5);
gl_FragColor = texture2D(texture,texCoord);
}Computing the derivatives would be something like:
uniform sampler2D texture;
uniform int2 screenRes; // resolution of the viewport
varying vec4 clipPos;
void main()
{
// project to cartesian coordinates and scale from [-1,1] to [0,1].
vec2 texCoord = clipPos.xy / clipPos.w * 0.5 + vec2(0.5);
// assume we only stored in the RG components the texture coordinates
vec2 center = texture2D(texture,texCoord).xy;
vec2 right = texture2D(texture,texCoord + vec2(1.0 / screenRes.x, 0)).xy;
vec2 bottom = texture2D(texture,texCoord+ vec2(0, 1.0 / screenRes.y)).xy;
// compute the partial derivatives
vec2 dx = (right - center) / screenRes.x;
vec2 dy = (bottom - center) / screenRes.y;
// compute the mipmap level
float level = -log2( max(length(dx), length(dy)) );
gl_FragColor = vec4(level); // debugging output.
}I hope this leads you in the right direction.

Best regards!
Edited by Tsus, 01 July 2012 - 03:12 AM.