This page was last updated: February 27, 2009
Pick NX, NY, and NZ such that each is a power of 2.
unsigned char TextureXY[NZ][NX][NY][4];
unsigned char TextureXZ[NY][NX][NZ][4];
unsigned char TextureYZ[NX][NY][NZ][4];
Note that:
unsigned char TextureXY[NZ][NX][NY][4];
means "NZ slices of an NX by NY 4-component texture".
These hold 4 components, not 3, because you will be using an alpha value as well.
void
FillXY( void )
{
int x, y, z, zz;
float alpha; // opacity at this voxel
float r, g, b; // running color composite
for( x = 0; x < NX; x++ )
{
for( y = 0; y < NY; y++ )
{
r = g = b = 0.;
for( zz = 0; zz < NZ; zz++ )
{
// which direction to fill:
if( Zside == PLUS )
z = zz;
else
z = ( NZ-1 ) - zz;
if( << this scalar value is not in the range you want to view >> )
{
r = g = b = 0.;
alpha = 0.;
}
else
{
r = Nodes[x][y][z].r;
g = Nodes[x][y][z].g;
b = Nodes[x][y][z].b;
alpha = MaxAlpha;
}
TextureXY[zz][y][x][0] = (unsigned char) ( 255.*r + .5 );
TextureXY[zz][y][x][1] = (unsigned char) ( 255.*g + .5 );
TextureXY[zz][y][x][2] = (unsigned char) ( 255.*b + .5 );
TextureXY[zz][y][x][3] = (unsigned char) ( 255.*alpha + .5 );
}
}
}
}
Depending on the rotation of the volume, you will want to draw the parallel planes in the X, Y, or Z direction, and draw them MINUS-to-PLUS or PLUS-to-MINUS. The following code tells you which of these cases is the one you will need.
// which way is a surface facing:
const int MINUS = { 0 };
const int PLUS = { 1 };
// what is the major direction:
#define X 0
#define Y 1
#define Z 2
. . .
int Major; // X, Y, or Z
int Xside, Yside, Zside; // which side is visible, PLUS or MINUS
. . .
//
// determine which sides of the cube are facing the user
//
// this assumes that the rotation is being done by:
//
// glRotatef( Yrot, 0., 1., 0. );
// glRotatef( Xrot, 1., 0., 0. );
//
void
DetermineVisibility()
{
float xr, yr;
float cx, sx;
float cy, sy;
float nzx, nzy, nzz; // z component of normal for x side, y side, and z side
xr = Xrot * ( M_PI/180. );
yr = Yrot * ( M_PI/180. );
cx = cos( xr );
sx = sin( xr );
cy = cos( yr );
sy = sin( yr );
nzx = -sy;
nzy = sx * cy;
nzz = cx * cy;
// which sides of the cube are showing:
// MINUS or PLUS tells us which side is facing the viewer
Xside = ( nzx > 0. ? PLUS : MINUS );
Yside = ( nzy > 0. ? PLUS : MINUS );
Zside = ( nzz > 0. ? PLUS : MINUS );
// which direction needs to be composited:
if( fabs(nzx) > fabs(nzy) && fabs(nzx) > fabs(nzz) )
Major = X;
else if( fabs(nzy) > fabs(nzx) && fabs(nzy) > fabs(nzz) )
Major = Y;
else
Major = Z;
}
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
filter = GL_NEAREST;
if( Bilinear )
filter = GL_LINEAR;
else
filter = GL_NEAREST;
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glEnable( GL_TEXTURE_2D );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glEnable( GL_BLEND );
if( Major == Z )
{
if( Zside == PLUS )
{
z0 = -1.;
dz = 2. / (float)( NZ - 1 );
}
else
{
z0 = 1.;
dz = -2. / (float)( NZ - 1 );
}
for( z = 0, zcoord = z0; z < NZ; z++, zcoord += dz )
{
glTexImage2D( GL_TEXTURE_2D, 0, 4, NX, NY, 0, GL_RGBA, GL_UNSIGNED_BYTE, &TextureXY[z][0][0][0] );
glBegin( GL_QUADS );
glTexCoord2f( 0.f, 0.f );
glVertex3f( -1.f, -1.f, zcoord );
glTexCoord2f( 1.f, 0.f );
glVertex3f( 1.f, -1.f, zcoord );
glTexCoord2f( 1.f, 1.f );
glVertex3f( 1.f, 1.f, zcoord );
glTexCoord2f( 0.f, 1.f );
glVertex3f( -1.f, 1.f, zcoord );
glEnd();
}
}
. . .
| Item | Points |
| 3D transformation | 10 |
| Correctly composites | 40 |
| Correctly changes compositing direction | 20 |
| Handles the S range correctly | 30 |
| Handles the opacity correctly | 30 |
| Potential Total | 130 |