I guess I described what I saw, poorly. I’m also getting ahead of myself. First, I don’t understand how the example works. Take a look at the sample Eosie linked to above:
http://www.codesampler.com/oglsrc/oglsrc_14.htm#ogl_multisample_transparency
If you are using X+GLX here is a replacement ogl_multisample_transparency.cpp:
//------------------------------------------------------------------------------
// Name: ogl_multisample_transparency.cpp
// Author: Kevin Harris
// Last Modified: 12/13/07
// Description: This sample demonstrates how to use multi-sample transparency
// to skip the typically necessary step of sorting all
// transparent geometry back to front. See the related sample
// "ogl_alpha_blending_texture" for the more typical setup which
// does require sorting.
//
// Control Keys: b - Toggle blending via multi-sample transparency
// Up Arrow - Move the test cube closer
// Down Arrow - Move the test cube away
//
// NOTE: This sample will not work correctly unless the driver has been set to
// use Antialiasing or Multisample Transparency. I can't tell you how to
// do this since every driver control panel does it a little differently.
// For my particular nVIDIA card, I need to set the Antialias level to 4X
// to get the sample to work correctly.
//
// --------------------------
// This file is not the original code by the above author. This has been ported
// to use X+GLX (Jason Cipriani).
//------------------------------------------------------------------------------
#include <X11/Xlib.h>
#include <GL/glx.h>
#include <GL/glu.h>
#include <stdio.h>
#include <stdlib.h>
#include "tga.h"
//-----------------------------------------------------------------------------
// GLOBALS
//-----------------------------------------------------------------------------
Display *g_XDisp;
int g_XScreen;
Window g_XWin;
GLXContext g_GLX;
GLuint g_textureID = -1;
bool g_bBlending = true;
float g_fDistance = -4.5f;
float g_fSpinX = 0.0f;
float g_fSpinY = 0.0f;
struct POINT { int x, y; };
struct Vertex
{
float tu, tv;
float x, y, z;
};
Vertex g_cubeVertices[] =
{
{ 0.0f,0.0f, -1.0f,-1.0f, 1.0f },
{ 1.0f,0.0f, 1.0f,-1.0f, 1.0f },
{ 1.0f,1.0f, 1.0f, 1.0f, 1.0f },
{ 0.0f,1.0f, -1.0f, 1.0f, 1.0f },
{ 1.0f,0.0f, -1.0f,-1.0f,-1.0f },
{ 1.0f,1.0f, -1.0f, 1.0f,-1.0f },
{ 0.0f,1.0f, 1.0f, 1.0f,-1.0f },
{ 0.0f,0.0f, 1.0f,-1.0f,-1.0f },
{ 0.0f,1.0f, -1.0f, 1.0f,-1.0f },
{ 0.0f,0.0f, -1.0f, 1.0f, 1.0f },
{ 1.0f,0.0f, 1.0f, 1.0f, 1.0f },
{ 1.0f,1.0f, 1.0f, 1.0f,-1.0f },
{ 1.0f,1.0f, -1.0f,-1.0f,-1.0f },
{ 0.0f,1.0f, 1.0f,-1.0f,-1.0f },
{ 0.0f,0.0f, 1.0f,-1.0f, 1.0f },
{ 1.0f,0.0f, -1.0f,-1.0f, 1.0f },
{ 1.0f,0.0f, 1.0f,-1.0f,-1.0f },
{ 1.0f,1.0f, 1.0f, 1.0f,-1.0f },
{ 0.0f,1.0f, 1.0f, 1.0f, 1.0f },
{ 0.0f,0.0f, 1.0f,-1.0f, 1.0f },
{ 0.0f,0.0f, -1.0f,-1.0f,-1.0f },
{ 1.0f,0.0f, -1.0f,-1.0f, 1.0f },
{ 1.0f,1.0f, -1.0f, 1.0f, 1.0f },
{ 0.0f,1.0f, -1.0f, 1.0f,-1.0f }
};
//-----------------------------------------------------------------------------
// PROTOTYPES
//-----------------------------------------------------------------------------
void loadTexture();
void init();
void render();
void shutDown();
//-----------------------------------------------------------------------------
// Name: main()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
int main (int argc, char **argv) {
XSetWindowAttributes attrs;
XEvent event;
XVisualInfo *vi;
POINT ptLastMousePosit;
POINT ptCurrentMousePosit;
bool bMousing;
g_XDisp = XOpenDisplay(NULL);
g_XScreen = DefaultScreen(g_XDisp);
g_XWin = XCreateWindow(g_XDisp, XRootWindow(g_XDisp, g_XScreen), 0, 0, 640,
480, 0, DefaultDepth(g_XDisp, g_XScreen), InputOutput,
DefaultVisual(g_XDisp, g_XScreen), 0, &attrs);
XSelectInput(g_XDisp, g_XWin, ExposureMask | ButtonPressMask | ButtonReleaseMask | Button1MotionMask | KeyPressMask);
XMapWindow(g_XDisp, g_XWin);
init();
do {
if (XPending(g_XDisp) > 0) {
XNextEvent(g_XDisp, &event);
if (event.type == KeyPress) {
int n = XKeycodeToKeysym(g_XDisp, event.xkey.keycode, (event.xkey.state & ShiftMask) ? 1 : 0);
if (n == 65307) // escape
break;
else if (n == 'b' || n == 'B')
g_bBlending = !g_bBlending;
else if (n == 65362) // up
g_fDistance += 0.1f;
else if (n == 65364) // down
g_fDistance -= 0.1f;
} else if (event.type == ButtonPress && event.xbutton.button == Button1) {
ptLastMousePosit.x = ptCurrentMousePosit.x = event.xbutton.x;
ptLastMousePosit.y = ptCurrentMousePosit.y = event.xbutton.y;
bMousing = true;
} else if (event.type == ButtonRelease && event.xbutton.button == Button1) {
bMousing = false;
} else if (event.type == MotionNotify) {
ptCurrentMousePosit.x = event.xmotion.x;
ptCurrentMousePosit.y = event.xmotion.y;
if( bMousing ) {
g_fSpinX -= (ptCurrentMousePosit.x - ptLastMousePosit.x);
g_fSpinY -= (ptCurrentMousePosit.y - ptLastMousePosit.y);
}
ptLastMousePosit.x = ptCurrentMousePosit.x;
ptLastMousePosit.y = ptCurrentMousePosit.y;
}
} else
render();
} while (1);
shutDown();
return 0;
}
//-----------------------------------------------------------------------------
// Name: loadTexture()
// Desc:
//-----------------------------------------------------------------------------
void loadTexture () {
tgaImageFile tgaImage;
tgaImage.load( "radiation_box.tga" );
glGenTextures( 1, &g_textureID );
glBindTexture( GL_TEXTURE_2D, g_textureID );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, tgaImage.m_texFormat,
tgaImage.m_nImageWidth, tgaImage.m_nImageHeight,
0, tgaImage.m_texFormat, GL_UNSIGNED_BYTE,
tgaImage.m_nImageData );
}
//-----------------------------------------------------------------------------
// Name: init()
// Desc:
//-----------------------------------------------------------------------------
void init () {
int attrs[] = {
GLX_RGBA,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 24,
GLX_DOUBLEBUFFER,
GLX_SAMPLE_BUFFERS_ARB, 1,
GLX_SAMPLES_ARB, 4,
None
};
XVisualInfo *vi;
if (!(vi = glXChooseVisual(g_XDisp, g_XScreen, attrs))) {
fprintf(stderr, "Could not find an acceptable pixel format!
");
exit(1);
}
if (!(g_GLX = glXCreateContext(g_XDisp, vi, NULL, True))) {
fprintf(stderr, "Could not create GLX context!
");
exit(1);
}
glXMakeCurrent(g_XDisp, g_XWin, g_GLX);
loadTexture();
glClearColor( 0.35f, 0.53f, 0.7f, 1.0f );
glEnable( GL_TEXTURE_2D );
//glColor4f(1.0, 1.0, 1.0, 0.25);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 45.0f, 640.0f / 480.0f, 0.1f, 100.0f);
}
//-----------------------------------------------------------------------------
// Name: shutDown()
// Desc:
//-----------------------------------------------------------------------------
void shutDown () {
glDeleteTextures(1, &g_textureID);
glXMakeCurrent(g_XDisp, None, NULL);
glXDestroyContext(g_XDisp, g_GLX);
}
//-----------------------------------------------------------------------------
// Name: render()
// Desc:
//-----------------------------------------------------------------------------
void render () {
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0.0f, 0.0f, g_fDistance );
glRotatef( -g_fSpinY, 1.0f, 0.0f, 0.0f );
glRotatef( -g_fSpinX, 0.0f, 1.0f, 0.0f );
if( g_bBlending == true )
{
glEnable( GL_DEPTH_TEST );
glEnable( GL_MULTISAMPLE_ARB );
glEnable( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB );
glBindTexture( GL_TEXTURE_2D, g_textureID );
glInterleavedArrays( GL_T2F_V3F, 0, g_cubeVertices );
glDrawArrays( GL_QUADS, 0, 24 );
}
else
{
glDisable( GL_MULTISAMPLE_ARB );
glDisable( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB );
glBindTexture( GL_TEXTURE_2D, g_textureID );
glInterleavedArrays( GL_T2F_V3F, 0, g_cubeVertices );
glDrawArrays( GL_QUADS, 0, 24 );
}
glXSwapBuffers(g_XDisp, g_XWin);
}
And here is a Makefile:
BIN = ogl_multisample_transparency
SRC = ogl_multisample_transparency.cpp
LIBS = -lX11 -lGL -lGLU
$(BIN): $(SRC)
g++ $(SRC) $(LIBS) -o $(BIN)
clean:
rm -f *~ $(BIN)
When you run it you should see a box with a semi-transparent texture on each face. You should be able to see through the box to the texture on the other side. This should work correctly no matter what orientation the box is in (use the mouse to rotate). Forget everything I said about dithering, triangles, and vertex colors for now. I have a basic question before anything else:
Can you tell me why I am able to see the far face of the cube through the near face of the cube even when GL_DEPTH_TEST is enabled? Why is the far face being rendered (regardless of orientation i.e. regardless of drawing order) even when it should be failing the depth test and be obscured / overwritten by the nearest faces?
Thanks,
Jason
P.S. Here is a replacement render() function for that example that shows the difference between using A2C+multisample vs. normal GL_BLEND:
void render () {
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0.0f, 0.0f, g_fDistance );
glRotatef( -g_fSpinY, 1.0f, 0.0f, 0.0f );
glRotatef( -g_fSpinX, 0.0f, 1.0f, 0.0f );
if( g_bBlending == true )
{
glEnable( GL_DEPTH_TEST );
glEnable( GL_MULTISAMPLE_ARB );
glEnable( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB );
glDisable(GL_BLEND);
glBindTexture( GL_TEXTURE_2D, g_textureID );
glInterleavedArrays( GL_T2F_V3F, 0, g_cubeVertices );
glDrawArrays( GL_QUADS, 0, 24 );
}
else
{
glDisable( GL_MULTISAMPLE_ARB );
glDisable( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB );
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture( GL_TEXTURE_2D, g_textureID );
glInterleavedArrays( GL_T2F_V3F, 0, g_cubeVertices );
glDrawArrays( GL_QUADS, 0, 24 );
}
glXSwapBuffers(g_XDisp, g_XWin); // or the other one for windows sample
}
Use ‘b’ to toggle between the two modes. Note that with GL_BLEND, as expected, depth testing prevents some faces from being rendered. Does enabling GL_MULTISAMPLE mess with depth testing or something…?