glPoint Alpha Blending issue - opengl

I am having issues alpha blending glPoints. The alpha blending works correctly when the glPoint is over the background but when a glPoint overlaps another glPoint the background color is visible rather then the underlying glPoint.
// create texture
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
// Draw
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, tex);
....
glDrawArrays(GL_POINTS, 0, numberOfPoints);
// Frag Shader
uniform sampler2D Texture;
void main(void)
{
gl_FragColor = texture2D(Texture, gl_PointCoord);
}
What am i doing wrong?

It looks like the depth test is causing your issues. What happens is, as you describe, a point in front is drawn first and the depth value is replaced. Then the point behind is rasterized but all the fragments fail the depth test so nothing more is rendered/blended.
As Andon M. Coleman pointed out, you really need to sort the fragments in order of depth for correct alpha blending (exact order independent transparency is currently impractical for particles although you could try some of the approximate techniques. averaging all colour using alpha values as a weight can give decent results too).
Especially for the particle density you have and the lack of variation among particles there probably won't be much difference between sorting and not sorting. In this case, make sure you draw all the opaque stuff first, with depth testing enabled and then draw the particles. You want to keep depth testing enabled so your particles aren't drawn when they're behind opaque things however you don't want them to obscure each other - you want to use the depth buffer for testing but not write depth values. For this, use glDepthMask

Related

Framebuffer clipping anything drawn 'off screen'

I recently implemented a zoom-in/zoom-out function in my simple 2D engine and experienced some terrible seams between adjacent textures, as shown here:
http://oi59.tinypic.com/anmxyf.jpg
It doesn't look that bad but it was definitely annoying when it was constantly blinking at you when moving around.
I decided to change it so a very large portion of the game (as much as the player is allowed to zoom out) is instead drawn on a framebuffer, then I print the framebuffer and when zooming in or out it instead increases/decreases the framebuffer texture size, as to avoid the seams.
At first I decided to draw 5 times as much as is visible to the player at default zoom, so I made a framebuffer object with a texture 5 times as big, then draw to it.
Here is the initialization of the framebuffer object:
glGenFramebuffers(1, &main_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, main_framebuffer);
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
glGenTextures(1, &main_ColorBuffer);
glBindTexture(GL_TEXTURE_2D, main_ColorBuffer);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA, SCREEN_BUFFER_WIDTH, SCREEN_BUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, main_ColorBuffer, 0
);
Where SCREEN_BUFFER_WIDTH and SCREEN_BUFFER_HEIGHT is set as five times as big as the default screen size. I then draw my world as I would normally do (where I could zoom out as much as I wanted and everything was fine, except the seams).
The issue is that only 1024 x 768 (being the default screen size) is drawn to the framebuffer. This is how I activate, draw to the framebuffer, then draw the framebuffer:
glBindFramebuffer(GL_FRAMEBUFFER, main_framebuffer);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw_blocks(); //draws all the blocks in the correct screen y and x position
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, main_ColorBuffer);
draw_quad(shift_y*ratio, shift_x*ratio, SCREEN_BUFFER_WIDTH*ratio, SCREEN_BUFFER_HEIGHT*ratio);
glBindTexture(GL_TEXTURE_2D, 0);
Where ratio is a float I use for zooming in and out and shift_y and shift_x I use to shift the framebuffer texture around to get a better feel for how things are going.
By zooming out and shifting the framebuffer a bit I get this:
http://oi61.tinypic.com/34zlpip.jpg
it only draws a small portion of the screen (which exactly fits the screen if I don't zoom out).
In contrast, this is what it looks like if I zoom all the way out (and then some) before using a framebuffer and instead drawing straight to the screen:
http://oi61.tinypic.com/21akbit.jpg (the empty parts are just chunks that haven't been loaded as the player isn't supposed to be able to zoom out this much).
I'm truly stumped here, I've tried changing the viewport before drawing but this does just about nothing.
I'd also like to note that I'm pretty confident the actual framebuffer texture object actually is five times as large as what's being drawn to it, because if I don't stretch it in my draw_quad function by instead giving it the same width and height as the screen, I get this:
http://oi62.tinypic.com/4triiu.jpg
The width and height of the framebuffer is now the same as the width and height of the screen, yet there's only graphics in a fraction of it, which is the small portion that's actually being drawn to.
Anyone have any clue? If more portions of code are needed I'm happy to oblige but the entire thing is far too much.

GLSL Partially Overlapping Textures

I'm trying to blend two partially overlapping textures in GLSL and am wondering if I'm misunderstanding the concept of multi-texturing. Is it required that the textures fully overlap or can you have two offset textures that blend only where they overlap?
I have two images similar to the following (minus grid lines and text):
Example image
Ideally, the overlapping sections of the image would blend together nicely so that the final result would look like one smooth image that combines the two together. Overlapping orange pixels, for example, would blend together or take the higher intensity.
I'm new to GLSL and have been using this article GLSL Shader Article which uses a fragment shader to blend the textures (fairly standard).
Following the article, I#m setting up each texture like so:
glUseProgramObjectARB( m_hProgramObject );
GLint nParamObj = glGetUniformLocationARB( m_hProgramObject, pParamName_i );
...
glActiveTexture(GL_TEXTURE0 + nTextureID_i );
glBindTexture(GL_TEXTURE_2D, nTextureID_i);
glUniform1iARB( nParamObj, nTextureID_i );
I then bind each texture and draw triangle strips. My textures are created as:
glBindTexture( GL_TEXTURE_2D, m_nTextureID );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glTexImage2D(GL_TEXTURE_2D, 0, 4, nWidth, nHeight, 0, GL_RGBA,
GL_UNSIGNED_BYTE, pbyData);
Does that process seem reasonable or am I misunderstanding the concept? Any tips or advice on how to achieve this?
That process certainly seems adequate. The advantage of using a fragment shader is you get complete control over how the textures are combined. For the offset, you may want two sets of texture coordinates - one for each image - or you could generate them implicitly. Figuring out what you want and writing the fragment shader will probably be the difficult bit. Unfortunately if you want to blend many different textures, the fragment shader used in this way can get quite expensive or just wont work with too many textures bound.
Your example image doesn't look like any blending has occurred at all - the images are just positioned over each other. In this case, it's easier just to draw separate bits of geometry with mapped textures.
Blending is typically done by the fixed pipeline blending stage. For example using the following calls...
glEnable(GL_BLEND)
glBlendFunc(src_scale, dest_scale)
One of the most common configuration is alpha blending with the over operator: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) in which the amount blended is given by the alpha value of the colour your drawing - possibly influenced by the A component in your GL_RGBA texture. You can further manipulate the blend equations if needed. See Blending.

Aliasing issue with SDL + OpenGL masking

I've been trying to make Worms style destructible terrain, and so far it's been going pretty well...
Snapshot1
I have rigged it so that the following image is masked onto the "chocolate" texture.
CircleMask.png
However, as can be seen on Snapshot 1, the "edges" of the CircleMask are still visible (overlapping each other). I'm fairly certain it has something to do with aliasing, as mask image is being stretched before being applied (that, and the SquareMask.png does not have this issue). This is my problem.
My masking code is as follows:
void MaskedSprite::draw(Point pos)
{
glEnable(GL_BLEND);
// Our masks should NOT affect the buffers color, only alpha.
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glBlendFunc(GL_ONE_MINUS_DST_ALPHA,GL_DST_ALPHA);
// Draw all holes in the texture first.
for (unsigned i = 0; i < masks.size(); i++)
if (masks.at(i).mask) masks.at(i).mask->draw(masks.at(i).pos, masks.at(i).size);
// But our image SHOULD affect the buffers color.
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Now draw the actual sprite.
Sprite::draw(pos);
glDisable(GL_BLEND);
}
The draw() function draws a quad with the texture on it to the screen. It has no blend functions.
If you invert the alpha channel on your mask image so that the inside of the circle has alpha 0.0, You can use the following blending mode:
glClearColor(0,0,0,1);
// ...
glBlendFunc(GL_DST_ALPHA, GL_ZERO);
This means, when the screen is cleared, each pixel will be set to alpha 1.0. Each time the mask is rendered with blending enabled, it will multiply the mask's alpha value with the current alpha at that pixel, so the alpha value will never increase.
Note that using this technique, any alpha channel in the sprite texture will be ignored. Also, if you are rendering a background before the terrain, you will need to change the blend function before rendering the final sprite image. Something like glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA) would work.
Another solution would be to use your blending mode but set the mask texture's interpolation mode to nearest-neighbor to ensure that each value sampled from the mask is either 0.0 or 1.0:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
My last bit of advice is this: the hard part about destructible 2D terrain is not getting it to render correctly, it's doing collision detection with it. If you haven't given thought to how you plan to tackle it, you might want to.

OpenGL - How to read Alpha from a texture

I want the alpha value to be read for each pixel from the texture, so that some pixels completely disappear. The texture file(targa format) does contain the proper alpha channel.
Screenshot: http://i43.tinypic.com/2i79s1x.png
Here are the options I am using:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGR, //changing GL_BGR to anything else doesn't do a thing :? also tried GL_BGRA.
GL_UNSIGNED_BYTE, targaImage);
I have also tried most of the combinations of parameters for the glBlendFunc but none achieves the effect, alhtough I might have skipped it. This is the one that gets the regular blending done right(based on the alpha from glColor):
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Rectangle drawing:
glColor4f(1,1,1,0.5);
mRect->Render();
If I set alpha to 1 it is fully opaque, but there is still white in the bottom right, meaning that the alpha is read from the texture but the white polygon beneath it is visible. So I need to make the polygon disappear somehow, but the texture to remain visible.
So that's how I achieve this in the picture. I have also experimented with this:
glAlphaFunc(GL_GREATER, 0.49);
glEnable(GL_ALPHA_TEST);
It only proves that the alpha of each ,,fragment'' of my rectangle is 0.5.
This texture file has a gradient that has full red around the blue circle in the middle, but the alpha goess from 0 in the top-left to full in the bottom-right(it's not the red color fading to white).
I would supply the whole code but it has more than 2k lines and I have split everything into classes, so I am just pulling out the parts I think are important.
Do I need my own shader to do this? I have only made my first contact with OpenGL and C++ a couple of weeks ago and I'm not into them yet, so if that's the solution I would appreciate a link to a tutorial that deals with alpha and GLSL.
Thank you :)
It looks like you're using the old, fixed function pipeline. With that you must properly configure the texture environment. Specifically you want the texture to modulate or replace the base color. Either is fine, but I presume replace mode is better suited for you.
After binding the texture set the mode using glTexEnvi, in your case specifically
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
Also I want to remind you, that you actually must enable blending (glEnable(GL_BLEND);)
If you look at the reference page for glTexEnv I think you easily grasp how ridiculously complex the state space for the fixed function texture environment pipeline became. I strongly suggest you don't bother with it and go directly for using the programmable pipeline, i.e. fragment shaders. Yes, their learning curve is significantly steeper, but with shaders you can actually write something legible like
#version 330
uniform sampler3D sampler_albedo;
uniform sampler2D sampler_diffuse;
out vec4 outcolor;
main()
{
float albedo = texture(sampler_albedo, texcood);
vec4 diffuse = texture(sampler_diffuse, texcoord);
outcolor = mix(basecolor, diffuse.rgb, diffuse.a) * albedo;
}
instead of spending over 15 lines setting up the texture environment and register combiners.

What user's framebuffer lacks?

Here is a comparison of same object using framebuffer texture projected onto screen and "main framebuffer"
Left image is bit blured while right is more sharp.Alos some options like glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ) do not work properly while rendering into the framebuffer.
My "pipeline" looks like this
Bind frambuffer
draw all geometry
Unbind
Draw on Quad like as texture.
So I wondering why "main frambufffer" can do this while "mine" can't? What are the differences between those two? Does user framebuffers skips some stages? Is it possible to match the quality of main buffer?
void Fbo::Build()
{
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
renderTexId.resize(nColorAttachments);
glGenTextures(renderTexId.size(),&renderTexId[0]);
for(int i=0; i<nColorAttachments; i++)
{
glBindTexture(format,renderTexId[i]);
glTexParameterf(format, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(format, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(format, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(format, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(format, 0, type, width, height, 0, type, GL_FLOAT, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,renderTexId[i], 0);
}
glBindTexture(GL_TEXTURE_2D, 0);
if(hasDepth)
{
glGenRenderbuffers(1, &depthBufferId);
glBindRenderbuffer(GL_RENDERBUFFER, depthBufferId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
//glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT24, width, height, 0,GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferId);
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
printf("FBO error, status: 0x%x\n", status);
}
}
Your "projection" of the FBO onto the screen is subject to sampler state, in particular the texture filter state is to blame here.
By default, if you simply bind the texture attachment you drew into from your FBO to a texture unit and apply it, it is going to use LINEAR sampling. This is different from blitting directly to the screen as would traditionally be the case if you were not using an FBO.
Default State table for Samplers in OpenGL:
http://www.opengl.org/registry/doc/glspec44.core.pdf pp. 541, Table 23.18 Textures (state per sampler object)
If you want to replicate the effect of drawing without an FBO, you would want to stretch a quad (or two triangles) over your viewport and use NEAREST neighbor sampling for your texture filter. Otherwise, it is going to sample adjacent texels in your FBO and interpolate them for each pixel on screen. This is the cause of your smoother image on the left side, which illustrates a form of anti-aliasing. It is worth mentioning that this is not even close to the same thing as MSAA or SSAA, which increase the sample rate when geometry is rasterized to fix undersampling errors, but it does achieve a similar effect.
Sometimes this is desirable, however. Many processing intensive algorithms run at 1/4, 1/8, or lower resolution and then use a bilinear or bilateral filter to upsample to the viewport resolution without the blockiness associated with nearest neighbor sampling.
The polygon mode state should work just fine. You will need to remember to set it back to GL_FILL before you draw your quad over the viewport though. Again, it all comes back to state management here - your quad will require some very specific states to produce consistent results. To render this way effectively you will probably have to implement a more sophisticated state management system / batch processor, you can no longer simply set glPolygonMode (...) once globally and forget it :)
UPDATE:
Thanks to datenwolf's comments, it should be noted that the above discussion of texture filtering was under the assumption your FBO was at a different resolution than the viewport you were trying to stretch it over.
If your FBO and viewport are at the same resolution, and you are still getting these artifacts from LINEAR texture filtering, then you have not setup your texture coordinates correctly. The problem in this scenario is that you are sampling your FBO texture at locations other than the texel centers and this is causing interpolation where none should be necessary.
Fragments are sampled at their centers (non-multisample) in GLSL by default, so if you setup your vertex texture coordinates and positions correctly you will not have to do any texel offset math on your per-vertex texture coordinates. Perspective projection can ruin your day if you are trying to do 1:1 mapping though, so you should either use orthographic projection, or better yet use NDC coordinates and no projection at all when you draw your quad over the viewport.
You can use the following vertex coordinates in Normalized Device Coordinates: (-1,-1,-1), (-1,1,-1), (1,1,-1),(1,-1,-1) for the 4 corners of your viewport if you replace the traditional modelview / projection matrices with an identity matrix (or simply do not multiply the vertex position by any matrix in your vertex shader).
You should also use CLAMP_TO_EDGE as your wrap state, because this will ensure you never generate texture coordinates outside the range of the center of the first texel and the center of the last texel in a given direction (s,t). CLAMP will actually generate values of 0 and 1 (which are not texel centers) for anything at or beyond the edges of the FBO texture attachment.
As a bonus, if you ALWAYS intend to render at 1:1 (FBO vs. viewport), you can avoid using per-vertex texture coordinates altogether and use gl_FragCoord. By default in GLSL, gl_FragCoord will give you the coordinate for the fragment center (0.5, 0.5), which also happens to be the corresponding texel center in your FBO. You can pass gl_FragCoord.st directly to your texture lookup in this special case.