[QUOTE=sueyllam;1256596]The code plots a surface with -1<=x<=1, -1<=y<=1< -1<=z<=1 in parametric form.
It allows rotating to see the surface from different viewpoints… Of course this could generalize to any ranges. The only problem is the choice of colors of the surface, probably turning the displayed color into shades of gray would look better…
#include <math.h>
#include <GL\glut.h>
GLint ww=500, wh=500;
int gbtn, gstate;
static GLfloat theta[] = {0.0,0.0,0.0};
static GLfloat normals[3];
static GLfloat viewer[]= {0.0, 0.0, 10.0}; /* initial viewer location */
static GLdouble x[4000000], y[4000000], f[4000000];
static int n=0;
static int inr[4000000];
int inner (GLfloat v1[], GLfloat v2[]) {
GLfloat p = 0.0;
for (int i=0; i<3; i++)
p += v1[i]*v2[i];
if (p<0)
return -1;
else if (p>0)
return 1;
else
return 0;
}
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
n = 0;
for (GLdouble u=-1.0; u<=1.0; u+=0.001) {
for (GLdouble t=-1.0; t<=1.0; t+=0.001) {
/*x*/y[n] = t*(u*u - t*t);
/*y*/x[n] = u;
/*f*/f[n] = u*u - t*t;
//x^2 - y^2 * Z^2 + Z^3 = 0
normals[0] = 2.0 * x[n];
normals[1] = -2.0 * y[n] * f[n] * f[n];
normals[2] = -2.0 * y[n] * y[n] * f[n] + 3.0 * f[n] * f[n];
GLfloat ray[3];
ray[0] = x[n];
ray[1] = y[n];
ray[2] = f[n];
inr[n++] = inner(ray, normals);
}
}
glEnable(GL_DEPTH_TEST);
}
void surface()
{
glBegin(GL_POINTS);
for (int i=0; i<n; i++) {
if (inr[i]>=0)
glColor3f((x[i]+1)*0.25, (y[i]+1)*0.25, (f[i]+1)*0.25);
else
glColor3f((x[i]+3)*0.25, (y[i]+3)*0.25, (f[i]+3)*0.25);
glVertex3d(x[i], y[i], f[i]);
}
glEnd();
}
void myDisplay(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
/* rotate surface */
glTranslatef(-viewer[0],-viewer[1],-viewer[2]);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0);
surface();
/* Use a perspective view */
glFlush();
glutSwapBuffers();
}
void
keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 'X':theta[0]+=1;
if (theta[0]==360) theta[0]=0;
break;
case 'x': theta[0]-=1;
if (theta[0]<0) theta[0] = 359;
break;
case 'Y':theta[1]+=1;
if (theta[1]==360) theta[1]=0;
break;
case 'y': theta[1]-=1;
if (theta[1]<0) theta[1] = 359;
break;
case 'Z':theta[2]+=1;
if (theta[2]==360) theta[2]=0;
break;
case 'z': theta[2]-=1;
if (theta[2]<0) theta[2] = 359;
break;
}
glutPostRedisplay ();
}
void mouse(int x, int y)
{
static int t=0, xp, yp;
if(gbtn==GLUT_LEFT_BUTTON && gstate == GLUT_DOWN) {
if (t==0) {
xp=x;
yp=y;
t=1;
return;
}
else {
theta[0]+=(y-yp); while (theta[0]>=360) theta[0]-=360; while (theta[0]<0) theta[0]+=360;
theta[1]+=(x-xp); while (theta[1]>=360) theta[1]-=360; while (theta[1]<0) theta[1]+=360;
xp=x;
yp=y;
}
}
else if(gbtn==GLUT_LEFT_BUTTON && gstate == GLUT_UP) {
t = 0;
return;
}
glutPostRedisplay();
}
void mouseClick(int btn, int state, int x, int y){
gbtn=btn;
gstate=state;
mouse(x,y);
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
ww=w;wh=h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h)
glOrtho(-2.4, 2.4, -2.4 * (GLfloat) h/ (GLfloat) w,
2.4* (GLfloat) h / (GLfloat) w, viewer[2]-1.8, viewer[2]+1.8);
else
glOrtho(-2.4* (GLfloat) w/ (GLfloat) h, 2.4* (GLfloat) w/ (GLfloat) h, -2.4,2.4, viewer[2]-1.8, viewer[2]+1.8);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(ww,wh);
glutInitWindowPosition(100, 100);
glutCreateWindow("3D Function Plot");
init();
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutMotionFunc(mouse);
glutMouseFunc(mouseClick);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}
[/QUOTE]
The colors get much better if you keep track of the ModelView matrix and compute the normal and ray according to it and not have them fixed according to original position.
Here the code that does that:
#include <math.h>
#include <GL\glut.h>
GLint ww=500, wh=500;
int gbtn, gstate;
static GLfloat theta[] = {0.0,0.0,0.0};
static GLfloat normals[4];
static GLfloat viewer[]= {0.0, 0.0, 10.0}; /* initial viewer location */
static GLdouble x[4000000], y[4000000], f[4000000];
static GLdouble mv[4][4];
static GLdouble trns[4][4]={{1.0,0.0,0.0,0.0},{0.0,1.0,0.0,0.0},{0.0,0.0,1.0,0.0},{0.0,0.0,0.0,1.0}};
static GLdouble rtx[4][4]={{1.0,0.0,0.0,0.0},{0.0,1.0,0.0,0.0},{0.0,0.0,1.0,0.0},{0.0,0.0,0.0,1.0}};
static GLdouble rty[4][4]={{1.0,0.0,0.0,0.0},{0.0,1.0,0.0,0.0},{0.0,0.0,1.0,0.0},{0.0,0.0,0.0,1.0}};
static GLdouble rtz[4][4]={{1.0,0.0,0.0,0.0},{0.0,1.0,0.0,0.0},{0.0,0.0,1.0,0.0},{0.0,0.0,0.0,1.0}};
//static GLdouble ac[4000000];
static int n=0;
void matmult (GLdouble m1[][4], GLdouble m2[][4], GLdouble m[][4]) {
GLdouble t=0.0;
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
t =0.0;
for (int k=0; k<4; k++) {
t += m1[i][k]*m2[k][j];
}
m[i][j] = t;
}
}
}
int inner (GLfloat v1[], GLfloat v2[]) {
GLfloat p = 0.0;
for (int i=0; i<3; i++)
p += v1[i]*v2[i];
if (p<0)
return -1;
else if (p>0)
return 1;
else
return 0;
}
void init(void)
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
n = 0;
for (GLdouble u=-1.0; u<=1.0; u+=0.001) {
for (GLdouble t=-1.0; t<=1.0; t+=0.001) {
/*x*/y[n] = t*(u*u - t*t);
/*y*/x[n] = u;
/*f*/f[n++] = u*u - t*t;
// ac[n] = (x[n]+y[n]+f[n])/3.0;
}
}
glEnable(GL_DEPTH_TEST);
}
void transform (GLfloat v[]) {
GLdouble t[4]={0.0, 0.0, 0.0, 0.0};
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
t[i] += mv[i][j]*v[j];
}
}
for (int i=0; i<4; i++) {
v[i] = t[i];
}
}
void surface()
{
glBegin(GL_POINTS);
for (int i=0; i<n; i++) {
//GLfloat c1 = (ac[n] + 1.0)*0.25;
//GLfloat c2 = (ac[n] + 3.0)*0.25;
GLfloat ray[4];
ray[0] = x[i];
ray[1] = y[i];
ray[2] = f[i];
ray[3] = 1.0;
//x^2 - y^2 * Z^2 + Z^3 = 0
normals[0] = 2.0 * x[i];
normals[1] = -2.0 * y[i] * f[i] * f[i];
normals[2] = -2.0 * y[i] * y[i] * f[i] + 3.0 * f[i] * f[i];
normals[3] = 1.0;
transform (ray);
transform (normals);
if (inner(ray, normals)>=0)
glColor3f((x[i]+1)*0.25, (y[i]+1)*0.25, (f[i]+1)*0.25);
//glColor3f(c1,c1,c1);
else
glColor3f((x[i]+3)*0.25, (y[i]+3)*0.25, (f[i]+3)*0.25);
//glColor3f(c2,c2,c2);
glVertex3d(x[i], y[i], f[i]);
}
glEnd();
}
void myDisplay(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
/* rotate surface */
GLdouble temp[4][4], temp1[4][4];
rtz[0][0] = rtz[1][1] = cos(theta[2]*3.14159265359/180.0);
rtz[1][0] = sin(theta[2]*3.14159265359/180.0);
rtz[0][1] = -rtz[1][0];
rtx[2][2] = rtx[1][1] = cos(theta[0]*3.14159265359/180.0);
rtx[2][1] = sin(theta[0]*3.14159265359/180.0);
rtx[1][2] = -rtx[2][1];
matmult(rtx, rtz, temp);
rty[2][2] = rtx[0][0] = cos(theta[1]*3.14159265359/180.0);
rty[0][2] = sin(theta[1]*3.14159265359/180.0);
rty[2][0] = -rty[0][2];
matmult(rty,temp, temp1);
trns[0][3] = -viewer[0];
trns[1][3] = -viewer[1];
trns[2][3] = -viewer[2];
matmult(trns, temp1, mv);
glTranslatef(-viewer[0],-viewer[1],-viewer[2]);
glRotatef(theta[1], 0.0, 1.0, 0.0);
glRotatef(theta[0], 1.0, 0.0, 0.0);
glRotatef(theta[2], 0.0, 0.0, 1.0);
surface();
glFlush();
glutSwapBuffers();
}
void
keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 'X':theta[0]+=1;
if (theta[0]==360) theta[0]=0;
break;
case 'x': theta[0]-=1;
if (theta[0]<0) theta[0] = 359;
break;
case 'Y':theta[1]+=1;
if (theta[1]==360) theta[1]=0;
break;
case 'y': theta[1]-=1;
if (theta[1]<0) theta[1] = 359;
break;
case 'Z':theta[2]+=1;
if (theta[2]==360) theta[2]=0;
break;
case 'z': theta[2]-=1;
if (theta[2]<0) theta[2] = 359;
break;
}
glutPostRedisplay ();
}
void mouse(int x, int y)
{
static int t=0, xp, yp;
if(gbtn==GLUT_LEFT_BUTTON && gstate == GLUT_DOWN) {
if (t==0) {
xp=x;
yp=y;
t=1;
return;
}
else {
theta[0]+=(y-yp); while (theta[0]>=360) theta[0]-=360; while (theta[0]<0) theta[0]+=360;
theta[1]+=(x-xp); while (theta[1]>=360) theta[1]-=360; while (theta[1]<0) theta[1]+=360;
xp=x;
yp=y;
}
}
else if(gbtn==GLUT_LEFT_BUTTON && gstate == GLUT_UP) {
t = 0;
return;
}
glutPostRedisplay();
}
void mouseClick(int btn, int state, int x, int y){
gbtn=btn;
gstate=state;
mouse(x,y);
}
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
ww=w;wh=h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h)
glOrtho(-2.4, 2.4, -2.4 * (GLfloat) h/ (GLfloat) w,
2.4* (GLfloat) h / (GLfloat) w, viewer[2]-1.8, viewer[2]+1.8);
else
glOrtho(-1.8* (GLfloat) w/ (GLfloat) h, 1.8* (GLfloat) w/ (GLfloat) h, -1.8, 1.8, viewer[2]-1.8, viewer[2]+1.8);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(ww,wh);
glutInitWindowPosition(100, 100);
glutCreateWindow("3D Function Plot");
init();
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutMotionFunc(mouse);
glutMouseFunc(mouseClick);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}