Render-to-Texture Problems v2

Started by CodeBunny, May 19, 2011, 00:19:55

Previous topic - Next topic

CodeBunny

I just noticed a bug in my code when I render to texture, and I'm not sure why it happens, so I thought I'd post it here.

I have a 256x256 brick wall texture, completely opaque. I also have a "bullet hole" texture that I render to sections of the texture whenever the brick
wall is "hit."

The problem occurs when the bullet hole texture has transparency. Where the image is completely transparent, everything is fine; and where the image is completely opaque, everything looks good. However, where the bullet hole is only partially transparent, it seems like the brick wall texture obtains the alpha value of the bullet hole, and becomes itself transparent.

Is this clear? I can go into more detail if necessary.

My blend function:
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);


My thoughts are that the alpha of the src image somehow replaces the alpha of the dst. Is this what happens? If so, what should I do to have appropriate alpha blending?

CodeBunny

Fixed, the call I needed for the src blending was GL_SRC_ALPHA_SATURATE. It now works like I want.

However, I'm curious as to why this is... Can someone enlighten me on why just using SRC_ALPHA caused that to happen?

EDIT: Actually, not true. All that does is put a black mark of varying transparency over the image. This is actually identical to the effect I wanted with the bullet hole, but when I re-tested with a color image, it was all blackened out.

spasi

I think more info is necessary to figure this out. Could you post samples of the 2 textures and the result you're getting? Also, knowing more about the rendering state would help, just the blending function is not enough. Do you use 2 passes or multitexturing? How's the texture environment set up?

CodeBunny

Alright.

Here's my brick image, and the bullet hole texture I'm trying to place onto it.

   

I'm trying to paint the bullet hole texture onto the brick wall to make it look like the bricks were "shot." An example of what I'm trying for:



For the most part, this is all working fine.

I'm rendering in 2D with depth and lighting disabled, and to render to the image I bind a framebuffer.

IntBuffer buffer = ByteBuffer.allocateDirect(4).order(
					ByteOrder.nativeOrder()).asIntBuffer();
			
			EXTFramebufferObject.glGenFramebuffersEXT(buffer);
			
			frameBuffersActive.push(buffer.get());
			
			EXTFramebufferObject.glBindFramebufferEXT(
					EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
					frameBuffersActive.peek());
			
			EXTFramebufferObject.glFramebufferTexture2DEXT(
					EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
					EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, 
					GL11.GL_TEXTURE_2D, 
					target,    // This is the ID of the texture to render to.
					0);

			checkFBO(frameBuffersActive.peek());

			GL11.glPushAttrib(GL11.GL_COLOR_BUFFER_BIT);
			GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
			GL11.glColor4f(1f, 1f, 1f, 1f);
			
			GL11.glPushAttrib(GL11.GL_VIEWPORT_BIT);
			GL11.glViewport(0, 0, width, height);
			
			GL11.glMatrixMode(GL11.GL_PROJECTION);
			GL11.glPushMatrix();
			GL11.glLoadIdentity();
			GL11.glOrtho(0, width, 0, height, -1, 1);
			
		    GL11.glMatrixMode(GL11.GL_MODELVIEW);
			GL11.glPushMatrix();
			GL11.glLoadIdentity();


This works, and exiting the framebuffer works fine as well.

To render the image, all I do is bind the framebuffer to the target texture, and then draw a textured quad at the desired location.

The problem is that the alpha values on the results aren't what I want.

Here's an example run, where the brick wall is on a vivid pink background:



You can see the pink through the brick wall around the bullet hole - basically, where the bullet hole has transparency, so does the resulting render.

Again, this is another result rendered in black over a white background (to show where the image is transparent):



After looking up more details on glBlendFunc(), I realized the problem is that using
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);

causes the alpha values to also be multiplied. This doesn't cause a problem if the source image has alpha of 0 or 1, but when it's in between the resulting pixels will also have an alpha value less than one.

So, what method of blending can I use to make the alpha blending work like I would want?

spasi

A couple of options you can try:

- Use glColorMask(true, true, true, false) when rendering to the framebuffer. Blending will still be performed correctly, but no alpha value will be written to the framebuffer texture. If the framebuffer was glCleared with a glClearColor(0.0f, 0.0f, 0.0f, 1.0f), then the alpha channel will remain "white".

- Disable blending when rendering the framebuffer texture.

Either of the above should fix your problem. Or, better yet, just do both to save on framebuffer bandwidth.

CodeBunny

glColorMask() worked. :D

Spasi, you've been a great help lately. Thank you very much.