This page was last updated: January 5, 2009
You have run a temperature simulation of a 3D room that has 4 heat sources. You are given the temperature data from the simulation at each node in a 3D grid. You will be creating several visualizations (in Projects 2, 3, 4, and 5) to understand the distribution of temperatures within the 3D room.
The number of node points you place within this region will be up to you.
The temperatures defined by the equation actually go
higher than 100 degrees in places, but don't worry about it.
After computing t, just clamp it to 100.:
const float TEMPMIN = { 0.f };
const float TEMPMAX = { 100.f };
. . .
if( t > TEMPMAX )
t = TEMPMAX;
#define NX ??? #define NY ??? #define NZ ???
const float GRAYMIN = { 0.20f };
const float GRAYMAX = { 1.00f };
. . .
if( t > TEMPMAX )
t = TEMPMAX;
float gray = GRAYMIN + ( GRAYMAX - GRAYMIN ) * ( t - TEMPMIN ) / ( TEMPMAX - TEMPMIN );
glColor3f( gray, gray, gray ); // r = g = b gives gray
I am going to let you "cheat" on the scalar data. Instead of reading it from a file as would normally be done, compute a scalar temperature value at each node point in each plane according to the following formula:
| i | Xi | Yi | Zi | Ai |
| 0 | 1.00 | 0.00 | 0.00 | 90.00 |
| 1 | -1.00 | 0.30 | 0.00 | 120.00 |
| 2 | 0.00 | 1.00 | 0.00 | 120.00 |
| 3 | 0.00 | 0.40 | 1.00 | 170.00 |
If you are comfortable with structures, a 3D array of structures is
a good way to store and access the data for this project:
struct node
{
float x, y, z; // location
float t; // temperature
float rgb[3]; // the assigned color (to be used later)
float rad; // radius (to be used later)
float grad; // total gradient (to be used later)
};
struct node Nodes[NX][NY][NZ];
If you are not comfortable with C structures, a 3D array for X, a 3D array for Y, etc. will work too.
InitGraphics() is a good place to set all these values. Fill the (x,y,z) components of each structure in the 3D array, and use those (x,y,z) to compute a temperature.
struct centers
{
float xc, yc, zc; // center location
float a; // amplitude
} Centers[] =
{
{ 1.00f, 0.00f, 0.00f, 90.00f },
{ -1.00f, 0.30f, 0.00f, 120.00f },
{ 0.00f, 1.00f, 0.00f, 120.00f },
{ 0.00f, 0.40f, 1.00f, 170.00f },
};
float
Temperature( float x, float y, float z )
{
float t = 0.0;
for( int i = 0; i < 4; i++ )
{
float dx = x - Centers[i].xc;
float dy = y - Centers[i].yc;
float dz = z - Centers[i].zc;
float rsqd = SQR(dx) + SQR(dy) + SQR(dz);
t += Centers[i].a * exp( -5.*rsqd );
}
if( t > TEMPMAX )
t = TEMPMAX;
return t;
}
Since there is no raise-to-a-power operator in C, and because the pow( ) function uses time-consuming logs and exponentials, the most efficient way to square something is to multiply it by itself. This can be messy-looking if the something is an expression. A way to clean this up and make the intent more obvious is to create a square-the-number function.
In C++, this is done quite nicely by putting these lines near the top of your program:
inline float SQR( float x )
{
return x * x;
}
In C (and C++), it can be done like this:
#define SQR(x) ( (x) * (x) )
although there is some danger in doing it this way. Since we are using C++ anyway, I would recommend that you do it the first way.
PointList = glGenLists( 1 );
glNewList( PointList, GL_COMPILE );
glPointSize( ?? ); // hardwire this, or set it with a spinner
glBegin( GL_POINTS );
for( int i = 0; i < NX; i++ )
{
float x = -1. + 2. * (float)i / (float)(NX-1);
for( int j = 0; j < NY; j++ )
{
float y = ???
for( int k = 0; k < NZ; k++ )
{
float z = ???
?????
glColor3f( ??? );
glVertex3f( ??? );
}
}
}
glEnd();
glEndList( );
. . .
glCallList( PointList );
. . .
| Item | Points |
| Correct points display | 20 |
| Correct grayscale distribution | 20 |
| Potential Total | 40 |