Skip to main content
gamedev.net
🔒 Locked

Blending Problem

Started by Sappharos 4 replies 1.1k views
Original Post
Sappharos
Sappharos
Okay, first off, I apologise for constantly posting so many questions on these forums. I post whenever I get really stuck. In this case hours of experimentation and searching haven't resulted in any success, so I feel it's necessary to ask here. I made a quick sample program to demonstrate the problem, and included a screenshot of it below. What I've done is first drawn an opaque, red quad on a black background (to show how transparent the other shapes are), then drawn two intersecting triangles in front of it, one blue, one yellow, both transparent. The blue triangle is drawn before the yellow. Where the yellow triangle lies in front of the blue one, blue colour still comes through. No problem. But where the blue one lies in front of the yellow, no colour at all is coming up from the yellow triangle (I've even checked the colours using MS Paint to make sure). It may look like a small problem, but it gets much more pronounced for example when I use entire models made up of transparent polygons. I'm really stumped. Blending Problem Here's the relevant sample of my code too, if it helps:

int InitGL(GLvoid)						// All Setup For OpenGL Goes Here
{
	glShadeModel(GL_SMOOTH);				// Enable Smooth Shading
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);			// Black Background
	glClearDepth(1.0f);					// Depth Buffer Setup
	glEnable(GL_DEPTH_TEST);				// Enables Depth Testing
	glDepthFunc(GL_LEQUAL);					// The Type Of Depth Testing To Do
	glEnable(GL_BLEND);					// Turn Blending On
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations
	return TRUE;						// Initialization Went OK
}

int DrawGLScene(GLvoid)						// Here's Where We Do All The Drawing
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);		// Clear Screen And Depth Buffer
    glLoadIdentity();						// Reset The Current Modelview Matrix
    glTranslatef(0.0f,-0.5f,-2.0f);				// Move Into The Screen 6.0 Units
    glBegin (GL_QUADS); // opaque red square
        glColor3f(1.0, 0.0, 0.0);
        glVertex3f(-0.5, 0.8, 0.0);
        glVertex3f( 0.5, 0.8, 0.0);
        glVertex3f( 0.5,-0.2, 0.0);
        glVertex3f(-0.5,-0.2, 0.0);
    glEnd();
    glEnable (GL_BLEND);
    //glDepthMask(false);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBegin (GL_TRIANGLES); // transparent blue triangle
        glColor4f(0.0, 1.0, 1.0, 0.25);
        glVertex3f(0.4, 1.05, 0.0);
        glVertex3f(-0.2, 0.65, 0.3);
        glVertex3f(0.4, 0.25, 0.0);
    glEnd();
    glBegin (GL_TRIANGLES); // transparent yellow triangle
        glColor4f(1.0, 1.0, 0.0, 0.5);
        glVertex3f(-0.4, 0.9, 0.0);
        glVertex3f(-0.4, 0.1, 0.0);
        glVertex3f(0.2, 0.5, 0.4);
    glEnd();
    //glDepthMask(true);
    glDisable (GL_BLEND);
    return TRUE;
}




There's probably something stupid about the above code, but I don't know what it is. Many thanks for your attention. [Edited by - Sappharos on March 22, 2009 6:29:51 PM]
Erik Rufelt
Erik Rufelt
This happens because of depth testing. When depth testing is enabled, even when the polygons are blended, the z-buffer will remove pixels drawn further away than those already visible on screen. To solve this problem you need to either disable depth-writes for transparent polygons, so that they can't hide each other by writing their z-values, or draw them in order of back to front, so the furthest away will be drawn first and the closer ones drawn on top afterward.
This will however not work if you have intersecting triangles, as in your example image. Usually you probably won't have that in your models, so it might not be a problem. Most models are made so that triangles only intersect at their edges.
If you have intersecting transparent polygons, so that two polygons have parts of them both in front of and behind the other, then you can't draw them correctly with depth-writes enabled.
elias4444
elias4444
You're running into a pretty typical problem. There's a few newer methods that get around the problem (check out Nvidia Depth Peeling), but your best bet to sort objects from back to front and render them in order (and just ignore the overlaps). Other than that, you can also detect the overlaps and then split the polygons into smaller chunks (can be computationally expensive thought).
Sappharos
Sappharos
Okay, thanks for your responses. [smile] I thought the fact that the triangles weren't intersecting properly meant I'd done something fundamentally wrong, that's why I raised the issue.

Quote:
Original post by Erik Rufelt
To solve this problem you need to either disable depth-writes for transparent polygons, so that they can't hide each other by writing their z-values, or draw them in order of back to front, so the furthest away will be drawn first and the closer ones drawn on top afterward.


Drawing from back to front would be very useful, but how do I do this without the depth buffer? Do I have to sort the polygons manually in the CPU?

[Edited by - Sappharos on March 23, 2009 2:09:04 AM]
Joshi9999
Joshi9999
You could cache all your alpha objects into a list, so that after you do all your opaque depth-testing and writing you can then run through and draw your alpha objects. You'd want to sort this list by depth (ie. farthest objects at the start (See Painter's Algorithm ) ), and then draw your objects doing your colour blending along the way.

I believe (Correct me if I am wrong), that with alpha blending on, they either render the intersected polygons twice, or they do z-testing on the pixel level, rather than the polygon level.

That's the theory behind it, though most API's have a render state that turns this sort of behaviour on.
Erik Rufelt
Erik Rufelt
Quote:
Original post by Sappharos
Drawing from back to front would be very useful, but how do I do this without the depth buffer? Do I have to sort the polygons manually in the CPU?


There are many different ways to do this, but yes you have to sort them. The easiest is to sort the polygons on the CPU, but it might not be fast. You can also try approximating by just disabling depth-writes after you have drawn all the non-blended geometry. If you only have some blended details it might not even be noticeable, depending on the alpha and blend function you use.
I don't have too much experience actually doing this beyond those simple methods. You could start a new topic specifically for it to get more responses. I'm sure there are many people on the forum that know the best ways of doing this.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.