I have an OpenGL texture rendered to a first FBO and I need to edit its brightness, render to a second FBO and then draw it on screen.
If I render the texture to the second FBO (without modifying its brightness) and then draw it on screen, it shows up correctly.
If I try to edit brightness of rendered texture (using texture combiner functions like glTexEnv) I get wrong output like all black or all white texture, altered contrast, ecc..
If I apply brightness regulation while drawing on screen instead of the FBO, it works great..brightness is modified as expected.
So my question is: can I use texture combiner functions like glTexEnv when I render to FBO?
This is the code which I use to modify brightness while drawing to the FBO (it doesn't work):
// "secondFBO" is the FBO I'm intended to render to after brightness regulation.
// "textureId" is the OpenGL texture attached to the first FBO that contains
// the unmodified texture.
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, secondFBO);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textureId);
// apply alpha filter
double t = brightnessValue;
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
if (t > 1.0f)
{
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
glColor4f(t-1, t-1, t-1, t-1);
}
else
{
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT);
glColor4f(1-t, 1-t, 1-t, 1-t);
}
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);
// ... draw texture ...
glDisable(GL_TEXTURE_RECTANGLE_ARB);
// restore previous state
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
// draw on screen
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
// "textureId2" is the texture attached to the second FBO
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, textureId2);
// ... draw texture ...
glDisable(GL_TEXTURE_RECTANGLE_ARB);
Why you are not using shaders?
I think it would be much easier to write the code
You are using FBO and that means that Shaders - at least GLSL 1.2 are supported by your hardware
Related
Here is a description of the problem:
I want to render some VBO shapes (rectangles, circles, etc) to an off screen framebuffer object. This could be any arbitrary shape.
Then I want to draw the result on a simple sprite surface as a texture, but not on the entire screen itself.
I can't seem to get this to work correctly.
When I run the code, I see the shapes being drawn all over the screen, but not in the sprite in the middle. It remains blank. Even though it seems like I set up the FBO with 1 color texture, it still only renders to screen even if I select the FBO object into context.
What I want to achieve is these shapes being drawn to an off screen texture (using an FBO, obviously) and then render it on the surface of a sprite (or a cube, or we) drawn somewhere on the screen. Yet, whatever I draw, appears to be drawn in the screen itself.
The tex(tex_object_ID); function is just a short-hand wrapper for OpenGL's standard texture bind. It selects a texture into current rendering context.
No matter what I try I get this result: The sprite is blank, but all these shapes should appear there, not on the main screen. (Didn't I bind rendering to FBO? Why is it still rendering on screen?)
I think it is just a logistics of setting up FBO in the right order that I am missing. Can anyone tell what's wrong with my code?
Not sure why the background is red, as I clear it after I select the FBO. It is the sprite that should get the red background & shapes drawn on it.
/*-- Initialization -- */
GLuint texture = 0;
GLuint Framebuffer = 0;
GLuint GenerateFrameBuffer(int dimension)
{
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, dimension, dimension, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glGenFramebuffers(1, &Framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, Framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glDrawBuffer(GL_COLOR);
glReadBuffer(GL_COLOR);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
console_log("GL_FRAMEBUFFER != GL_FRAMEBUFFER_COMPLETE\n");
return texture;
}
// Store framebuffer texture (should I store texture here or Framebuffer object?)
GLuint FramebufferHandle = GenerateFrameBuffer( 256 );
Standard OpenGL initialization code follows, memory is allocated, VBO's are created and bound, etc. This works correctly and there aren't errors in initialization. I can render VBOs, polygons, textured polygons, lines, etc, on standard double buffer with success.
Next, in my render loop I do the following:
// Possible problem?
// Should FramebufferHandle be passed here?
// I tried "texture" and "Framebuffer " as well, to no effect:
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferHandle);
// Correct projection, just calculates the view based on current zoom
Projection = setOrthoFrustum(-config.zoomed_width/2, config.zoomed_width/2, -config.zoomed_height/2, config.zoomed_height/2, 0, 100);
View.identity();
Model.identity();
// Mini shader, 100% *guaranteed* to work, there are no errors in it (works normally on the screen)
shaderProgramMini.use();
//Clear frame buffer with blue color
glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT);
// Set yellow to draw different shapes on the framebuffer
color = {1.0f,1.0f,0.0f};
// Draw several shapes (already correctly stored in VBO objects)
Memory.select(VBO_RECTANGLES); // updates uniforms
glDrawArrays(GL_QUADS, 0, Memory.renderable[VBO_RECTANGLES].indexIndex);
Memory.select(VBO_CIRCLES); // updates uniforms
glDrawArrays(GL_LINES, 0, Memory.renderable[VBO_CIRCLES].indexIndex);
Memory.select(VBO_2D_LIGHT); // updates uniforms
glDrawArrays(GL_LINES, 0, Memory.renderable[VBO_2D_LIGHT].indexIndex);
// Done writing to framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Correct projection, just calculates the view based on current zoom
Projection = setOrthoFrustum(-config.zoomed_width/2, config.zoomed_width/2, -config.zoomed_height/2, config.zoomed_height/2, 0, 100);
View.identity();
Model.identity();
Model.scale(10.0);
// Select texture shader to draw what was drawn on offscreen Framebuffer / texture
// Standard texture shader, 100% *guaranteed* to work, there are no errors in it (works normally on the screen)
shaderProgramTexture.use();
// This is a wrapper for bind texture to ID, just shorthand function name
tex(texture); // FramebufferHandle; // ? // maybe the mistake in binding to the wrong target object?
color = {0.5f,0.2f,0.0f};
Memory.select(VBO_SPRITE); Select a square VBO for rendering sprites (works if any other texture is assigned to it)
// finally draw the sprite with Framebuffer's texture:
glDrawArrays(GL_TRIANGLES, 0, Memory.renderable[VBO_SPRITE].indexIndex);
I may have gotten the order of something completely wrong. Or FramebufferHandle/Framebuffer/texture object is not passed to something correctly. But I spent all day, and hope someone more experienced than me can see the mistake.
GL_COLOR is not an accepted value for glDrawBuffer
See OpenGL 4.6 API Compatibility Profile Specification, 17.4.1 Selecting Buffers for Writing, Table 17.4 and Table 17.5, page 628
NONE, FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT, FRONT, BACK, LEFT, RIGHT, FRONT_AND_BACK, AUXi.
Arguments to DrawBuffer when the context is bound to a default framebuffer, and the buffers they indicate. The same arguments are valid for ReadBuffer, but only a single buffer is selected as discussed in section.
COLOR_ATTACHMENTi
Arguments to DrawBuffer(s) and ReadBuffer when the context is bound to a framebuffer object, and the buffers they indicate. i in COLOR_ATTACHMENTi may range from zero to the value of MAX_COLOR_ATTACHMENTS minus one.
Thsi means that glDrawBuffer(GL_COLOR); and glReadBuffer(GL_COLOR); will generate a GL_INVALID_ENUM error.
Try to use COLOR_ATTACHMENT0 instead.
Furthermore, glCheckFramebufferStatus(GL_FRAMEBUFFER), checkes the completeness of the framebuffer object which is bound to the target.
This means that
glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE
has to be done before
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Or you have to use:
glNamedFramebufferReadBuffer(Framebuffer, GL_FRAMEBUFFER);
I have got several meshes (~100) of the same complex object in various poses with slightly different rotation and translation parameters. The object consists of multiple rigid components like arms and legs.
The goal is to generate a unique grayscale picture showing the accumulation of these poses for a particular body part. The heat-map obtained gives an idea of probable pixel locations for the body part, where white represents maximum probability, and black minimum (the lighter the higher probability). Say I'm interested in the accumulation of the legs. If many leg pose samples lie on the same (x,y) pixel location, than I expect to see light pixels there. Ultimately the leg poses might not exactly overlap, so I also expect to see a smooth transition to the black low probability around the leg silhouette boundaries.
To solve this task I have decided to use rendering in OpenGL frame buffers as these are known to be computationally cheap, and because I need to run this accumulation procedure very often.
What I did is the following. I accumulate the corresponding renderings of the body part I'm interested in (let's still keep the leg example) on the same frame buffer 'fboLegsId' using GL_BLEND. In order to discriminate between the legs
and the rest of the body, I texture the mesh with two colors:
rgba(gray,gray,gray,255) for the legs, where gray = 255 / Number of samples = 255/100
rgba(0,0,0,0) for the rest of the body
Then I accumulate the 100 renderings (which for the leg should sum up to white = 255) by doing the following:
glBindFramebuffer(GL_FRAMEBUFFER, fboLegsId);
glClearColor(0,0,0,255);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
for each sample s = 0...100
mesh.render(pose s);
end
glReadPixels(...)
This performs almost as I expected. I do obtain the smooth grayscale heat-map I wanted. However there are self-occlusion problems
which arise even when I use only 1 sample. Say for a single pose sample, one of the arms moved before the leg, partially occluding them. I expect the influence of the occluded leg parts to be cancelled during rendering. However it renders as if the arm is invisible/translucent, allowing for pixels behind to be fully shown. This leads to wrong renderings and therefore wrong accumulations.
If I simple disable blending, I see the correct self-occlusion aware result. So, apparently the problem lies somewhere at blending time.
I also tried different blending functions, and so far the following one produced the closer results to a self-occlusion aware accumulation approach:
glBlendFunc(GL_ONE, GL_SRC_ALPHA);
Anyway there is still a problem here: one single sample looks now correct; two or more accumulated samples instead show overlapping artefacts with other samples. It looks like each accumulation replaces the current buffer pixel if the pixel is not part of the legs. And if the leg was found many times in front of the (let's say) the arm, than it becomes darker and darker, instead of lighter and lighter.
I tried to fix this by clearing depth buffer at each rendering iteration enabling depth computations, but this did not solve the problem.
I feel like there is either something conceptually wrong in my approach, or a small mistake somewhere.
I've tried a different approach based on the suggestions which performs as expected. Now I'm working with 2 frame buffers. The first one (SingleFBO) is used to render single samples with correct self-occlusion handling. The second (AccFBO) is used to accumulate the 2D textures from the first buffer using blending. Please, check my code below:
// clear the accumulation buffer
glBindFramebuffer(GL_FRAMEBUFFER, AccFBO);
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for each sample s = 0...100
{
// set rendering destination to SingleFBO
glBindFramebuffer(GL_FRAMEBUFFER, SingleFBO);
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
mesh->render(pose s);
glDisable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
// set rendering destination to the accumulation buffer
glBindFramebuffer(GL_FRAMEBUFFER, AccFBO);
glClear(GL_DEPTH_BUFFER_BIT);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
// draw texture from previous buffer to a quad
glBindTexture(GL_TEXTURE_2D, textureLeg);
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDepthMask(GL_FALSE);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glBegin( GL_QUADS );
{
glTexCoord2f(0,0); glVertex2f(-1.0f, -1.0f);
glTexCoord2f(1,0); glVertex2f(1.0f, -1.0f);
glTexCoord2f(1,1); glVertex2f(1.0f, 1.0f);
glTexCoord2f(0,1); glVertex2f(-1.0f, 1.0f);
}
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
// restore
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
glBindFramebuffer(GL_FRAMEBUFFER, AccFBO);
glReadPixels(...)
Please, check also my (standard) code for initializing the SingleFBO (similarly for AccFBO):
// create a texture object
glGenTextures(1, &textureLeg);
glBindTexture(GL_TEXTURE_2D, textureLeg);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// create a renderbuffer object to store depth info
glGenRenderbuffers(1, &rboLeg);
glBindRenderbuffer(GL_RENDERBUFFER, rboLeg);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// create a framebuffer object
glGenFramebuffers(1, &SingleFBO);
glBindFramebuffer(GL_FRAMEBUFFER, SingleFBO);
// attach the texture to FBO color attachment point
glFramebufferTexture2D(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER
GL_COLOR_ATTACHMENT0, // 2. attachment point
GL_TEXTURE_2D, // 3. tex target: GL_TEXTURE_2D
textureLeg, // 4. tex ID
0); // 5. mipmap level: 0(base)
// attach the renderbuffer to depth attachment point
glFramebufferRenderbuffer(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER
GL_DEPTH_ATTACHMENT, // 2. attachment point
GL_RENDERBUFFER, // 3. rbo target: GL_RENDERBUFFER
rboLeg); // 4. rbo ID
// check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
error(...);
// switch back to window-system-provided framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Here's a different approach:
Create two frame buffers: normal and acc. normal frame buffer should have a texture storage (with glFramebufferTexture2D).
Here's the basic algorithm:
Clear acc to black
Bind normal, clear to black, and render scene with white legs, and other parts black
Bind acc, render a full screen rectangle, with normal texture on it, with blend mode GL_ONE, GL_ONE
Forward the animation, and if it haven't finished, goto 2.
You have the result in acc
So, basically, acc will contain the individual frames summed.
If I render a scene in openGL, is it possible to get back the texture coordinates that were used to paint that pixel?
For example, if I render a triangle that has 3 vertices (x,y,z) and 3 tex coords (u,v), and then I select a pixel on the triangle, I can get the color of the triangle and the depth using opengl calls, but is it possible to also get the interpolated texture coordinate?
Basically, I want to get the image point on the texture that was used to paint the triangle at a particular pixel.
I am guessing the only real way to do this is by reconstructing the ray that goes from the camera center through the pixel on the image plane, and then do a ray-triangle intersection to figure out which triangle it was, and then I can do a lookup into my texture array to get the texture coordinates of the triangle, and then do my own barycentric interpolation, but I would like to avoid having to do all that if possible.
Edit: The code I currently have didn't appear properly formatted in the bounty request below, so I've put it here. This is what I have right now, I would like to add reading texture coordinates u,v to it, ideally without a shader program if possible.
// First initialize the FBO, I am interested in depth and color
// create a framebuffer object
glGenFramebuffers(1, &id);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
// Create texture to store color info
glGenTextures(1, &color);
glBindTexture(GL_TEXTURE_2D, color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, color, 0);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
// Create render buffer to store depth info
glGenRenderbuffers(1, &depth);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
// Attach the renderbuffer to depth attachment point
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
// Then later in the code, I use the actual buffer:
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboId);
...
//draw model
...
//read color and depth values (want to also read texture coordinate values u and v here too)
...
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
If you are determined to do this without using shaders, you could render your scene without lighting and using a single texture for every object. This texture would be filled with two gradients. The red channel would go from 0 to 255 horizontally and the green channel would go from 0 to 255 vertically. Now you have effectively painted the scene using the texture coordinates (assuming they are in the range 0-1). You can use glReadPixels to read back the buffer (or part of the buffer) you have just rendered to and use the red channel to retrieve u and the green channel to retrieve v.
Render your scene to a FBO with a 2-channel floating-point color attachment (GL_RG32F or similar) and output the u/v coordinates to that attachment in the fragment shader.
I'm attempting to load two textures and then switch between the two in my display function. I am using the SOIL library to load the textures as such:
tex_2 = SOIL_load_OGL_texture
(
"s9.png",
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS | SOIL_FLAG_COMPRESS_TO_DXT
);
tex_1 = SOIL_load_OGL_texture
(
"s8.png",
SOIL_LOAD_AUTO,
SOIL_CREATE_NEW_ID,
SOIL_FLAG_MIPMAPS | SOIL_FLAG_COMPRESS_TO_DXT
);
And then I use
glBindTexture(GL_TEXTURE_2D, tex_1)
or
glBindTexture(GL_TEXTURE_2D, tex_2);
To switch between the two. The problem is I must be loading them incorrectly and I'm not sure how. Whichever texture I load in last (tex_1 in the code above) is the the texture that I get for both tex_1 and tex_2 when I try to switch with glBindTexture. Any ideas?
Before loading the teaxtures I set up blending and turn on texture and sprites
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE);
glEnable(GL_TEXTURE_2D);
glEnable(GL_POINT_SPRITE);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Then in my display function, I loop over all my points which I want to draw and attempt to change the current texture before drawing the point with glVertex3f:
for(int i=0; i<num_particles; i++)
{
//select texture to use
if(class[i] == 2.0f)
glBindTexture(GL_TEXTURE_2D, tex_2);
else
glBindTexture(GL_TEXTURE_2D, tex_1);
glVertex3f(posn[3*i], posn[3*i+1], posn[3*i+2]);
}
The goal is I have two types of points and the sprite to be drawn at each point depends on the class the point is in
for(int i=0; i<num_particles; i++)
{
//select texture to use
if(class[i] == 2.0f)
glBindTexture(GL_TEXTURE_2D, tex_2);
else
glBindTexture(GL_TEXTURE_2D, tex_1);
glVertex3f(posn[3*i], posn[3*i+1], posn[3*i+2]);
}
You can't call glBindTexture() inside a glBegin()/glEnd() pair:
GL_INVALID_OPERATION is generated if glBindTexture is executed between the execution of glBegin and the corresponding execution of glEnd.
The last successful glBindTexture() was probably in the most recent SOIL_load_OGL_texture() call. That's why tex_1 and tex_2 seem to contain the same texture data: tex_2 is never rebound.
As previous answers: you cannot change textures between glBegin/glEnd.
What can you do then?
sort your particles by material... in this case by your texture. Set the first texture, draw particles (glBegin/glEnd), then set the second texture and draw remaining particles.
use texture atlases - http://en.wikipedia.org/wiki/Texture_atlas. Here is some more advanced usage: http://www.popcornfx.com/wiki/index.php/Particle_tutorial_smoke
that way you will have one texture, but you will have to set different texture coordinates...
I'm trying to blur a depth texture by blurring & blending mipmap levels in a fragment shader.
I have two frambuffer objects:
1) A color frambuffer with a depth renderobject attached.
2) A z framebuffer with a depth texture attached.
Once I render the scene to the color framebuffer object, I then blit to the depth buffer object, and can successfully render that (output is a GL_LUMINANCE depth texture).
I can successfully access any given mipmap level by selecting it prior to drawing the depth buffer, for example, I can render mipmap level 3 as follows:
// FBO setup - all buffer objects created successfully and are complete and the color
// framebuffer has been rendered to (it has a depth renderbuffer attached), and no
// OpenGL errors are issued:
glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo_color);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo_z);
glBlitFramebuffer(0,0,_w, _h, 0, 0, _w, _h, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
glGenerateMipmap(GL_TEXTURE_2D);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// This works:
// Select mipmap level 3
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 3);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 3);
draw_depth_texture_on_screen_aligned_quad();
// Reset mipmap
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1000);
As an alternative, I'd like to add the bias parameter to the texture2D() GLSL function, or use texture2DLod() and operate with a single texture sampler, but whenever I choose a level over than 0, it appears that the mipmap hasn't been generated:
// fragment shader (Both texture2DLod and texture2D(sampler, tcoord, bias)
// are behaving the same.
uniform sampler2D zbuffer;
uniform int mipmap_level;
void main()
{
gl_FragColor = texture2DLod(zbuffer, gl_TexCoord[0].st, float(mipmap_level));
}
I am not sure how the mipmapping works with the glBlitFramebuffer(), but my question is what is the proper way to setup the program such that calls made to texture2D/texture2DLod give the expected results?
Thanks, Dennis
Ok - I think I've got it... My depth buffer didn't have the mipmap levels generated. I'm using multi-texturing, and during rendering, I am activating texture unit 0 for the color framebuffer texture, and texture unit 1 for the depth buffer texture. When I activate/bind the textures, I call glGenerateMipmap(GL_TEXTURE_2D) as follows:
glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, _color_texture);
glGenerateMipmap(GL_TEXTURE_2D);
glActiveTextureARB(GL_TEXTURE1_ARB);
glBindTexture(GL_TEXTURE_2D, _zbuffer_texture);
glGenerateMipmap(GL_TEXTURE_2D);
When this is done, increasing the bias in the texture2D(sampler, coord, bias) gives fragments from the mipmap level as expected.