The attached program illustrates a shading anomaly we have encountered while attempting to use autonormal in conjunction with nurbs.
The shading of the sphere is seriously screwed up while running with indirect rendering on the standard X server packaged with RH 7.3. It can be fixed by uncommenting the /* #define CORRECT 1 */ on line 8. The correction just sets normals manually. The program runs fine on both native SGI systems and with the accelerated NV driver + XFree86 + Linux. Oddly enough the EXACT problem that occurs with unaccelerated rendering on XFree86 also occurs with the OpenGL version that comes with recent Sun Solaris boxes. Thus we may well have a bug that is simply latent on SGI | NV. If anyone sees it we would be interested in knowing what it is. Thanks, Mike James M. Westall Professor of Computer Science Clemson University Clemson SC 29634
/* * a sphere the hard way ... * 2d nurb surface as profile_curve x swing_curve ... * glEnable(GL_AUTO_NORMAL) doesn't seem to work on Linux systems; * uncomment the #define CORRECT below to see correct display */ /* #define CORRECT 1 */ #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xos.h> #include <X11/Xatom.h> #include <stdio.h> #include <math.h> #include <GL/gl.h> #include <GL/glx.h> #include <GL/glu.h> int vattrib[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE,8, GLX_GREEN_SIZE,8, GLX_BLUE_SIZE,8, GLX_DEPTH_SIZE,1, /* at least 1 means get largest */ None}; void do_display(); void nurbcity(); void do_material(); void do_lights(); main(argc,argv) int argc; char **argv; { Display *display; Window rootw, win; XSizeHints whisper; XEvent report; unsigned long eventmask; int screen, width, height, bsz; XVisualInfo *pgob; XSetWindowAttributes attrib; GLXContext ctx; XColor white, black; if((display=XOpenDisplay(NULL))==NULL){ fprintf(stderr,"can't open\n"); exit(1); } screen = DefaultScreen(display); width = 900; height = 900; rootw = RootWindow(display,screen); pgob = glXChooseVisual(display,screen,vattrib); attrib.colormap = XCreateColormap(display,rootw,pgob->visual,AllocNone); white.red = 0xffff; white.green = 0xffff; white.blue = 0xffff; black.red = 0; black.green = 0; black.blue = 0; XAllocColor(display,attrib.colormap,&white); XAllocColor(display,attrib.colormap,&black); attrib.background_pixel = white.pixel; attrib.border_pixel = black.pixel; bsz=0; win = XCreateWindow(display,rootw,0,0,width,height,bsz,pgob->depth,InputOutput,pgob->visual,CWBorderPixel|CWColormap|CWBackPixel,&attrib); ctx = glXCreateContext(display,pgob,NULL,True); glXMakeCurrent(display,win,ctx); /* whisper some hints to strange Tom */ whisper.flags = PSize; whisper.width=width; whisper.height=height; XSetWMNormalHints(display,win,&whisper); eventmask=ExposureMask|KeyPressMask; XSelectInput(display,win,eventmask); XMapWindow(display,win); /* wait on expose */ XNextEvent(display,&report); while(report.type!=Expose) { printf("do wah\n"); XNextEvent(display,&report); } while(1){ switch(report.type){ case Expose: do_display(); glXSwapBuffers(display,win); break; case KeyPress: glXDestroyContext(display,ctx); XCloseDisplay(display); exit(0); default: sleep(1); } XNextEvent(display,&report); } } struct point { float x; float y; float z; }; void do_display() { struct point eyept, viewpt, up; eyept.x = 0.0; eyept.y = 0.0; eyept.z = 5.0; viewpt.x = 0.0; viewpt.y = 0.0; viewpt.z = 0.0; up.x = 0.0; up.y = 1.0; up.z = 0.0; glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); glClearColor(0.3,0.0,0.3,0.0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* carve out gob */ gluPerspective(45.0,1.0,0.1,20.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(eyept.x,eyept.y,eyept.z,viewpt.x,viewpt.y,viewpt.z,up.x,up.y,up.z); #ifndef CORRECT glEnable(GL_AUTO_NORMAL); #endif glEnable(GL_NORMALIZE); do_material(); do_lights(); nurbcity(); } /* control points and degree in each direction */ /* swing curve ... u */ #define N 9 #define K 2 /* profile curve ... v */ #define M 5 #define L 2 /* swing in x-z plane */ struct point swing_crtl_pts[N] = { {1.0,0.0,0.0}, {1.0,0.0,1.0}, {0.0,0.0,1.0}, {-1.0,0.0,1.0}, {-1.0,0.0,0.0}, {-1.0,0.0,-1.0}, {0.0,0.0,-1.0}, {1.0,0.0,-1.0}, {1.0,0.0,0.0} }; /* profile in x-y plane */ struct point profile_crtl_pts[M] = { {0.0,1.0,0.0}, {1.0,1.0,0.0}, {1.0,0.0,0.0}, {1.0,-1.0,0.0}, {0.0,-1.0,0.0} }; float swing_weights[N] = { 1.0,M_SQRT1_2, 1.0,M_SQRT1_2, 1.0,M_SQRT1_2, 1.0,M_SQRT1_2, 1.0}; float profile_weights[M] = { 1.0,M_SQRT1_2, 1.0,M_SQRT1_2, 1.0}; float uknots[N+K+1] = { 0.0,0.0, 0.0,0.25, 0.25,0.5, 0.5,0.75, 0.75,1.0, 1.0,1.0}; float vknots[M+L+1] = { 0.0,0.0, 0.0,0.5, 0.5,1.0, 1.0,1.0}; float w_crtl_pts[N][M][4]; void nurbcity() { GLUnurbsObj *theNurb; int i, j, ustride, vstride; float dawt; for(i=0;i<N;i++){ for(j=0;j<M;j++){ dawt = swing_weights[i]*profile_weights[j]; w_crtl_pts[i][j][0] = swing_crtl_pts[i].x*profile_crtl_pts[j].x *dawt; w_crtl_pts[i][j][1] = profile_crtl_pts[j].y*dawt; w_crtl_pts[i][j][2] = swing_crtl_pts[i].z*profile_crtl_pts[j].x *dawt; w_crtl_pts[i][j][3] = dawt; } } ustride = M*4; vstride = 4; theNurb = gluNewNurbsRenderer(); gluNurbsProperty(theNurb,GLU_SAMPLING_TOLERANCE,25.0); gluBeginSurface(theNurb); /* on Linux, we seem to need specific normals */ #ifdef CORRECT gluNurbsSurface(theNurb,N+K+1,uknots,M+L+1,vknots,ustride,vstride, &w_crtl_pts[0][0][0],K+1,L+1,GL_MAP2_NORMAL); #endif gluNurbsSurface(theNurb,N+K+1,uknots,M+L+1,vknots,ustride,vstride, &w_crtl_pts[0][0][0],K+1,L+1,GL_MAP2_VERTEX_4); gluEndSurface(theNurb); } /* white light */ GLfloat light0_ambient[] = { 0.2, 0.2, 0.2, 0.0 }; GLfloat light0_diffuse[] = { 1.0, 1.0, 1.0, 0.0 }; GLfloat light0_specular[] = { 1.0, 1.0, 1.0, 0.0 }; GLfloat light0_position[] = { 4.0, 4.0, 4.0, 1.0 }; GLfloat light0_direction[] = { -1.0,-1.0,-1.0, 1.0}; void do_lights() { /* make specular correct for spots */ glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,1); glLightfv(GL_LIGHT0,GL_AMBIENT,light0_ambient); glLightfv(GL_LIGHT0,GL_DIFFUSE,light0_diffuse); glLightfv(GL_LIGHT0,GL_SPECULAR,light0_specular); glLightfv(GL_LIGHT0,GL_POSITION,light0_position); glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,light0_direction); glLightf(GL_LIGHT0,GL_SPOT_EXPONENT,1.0); glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,60.0); glLightf(GL_LIGHT0,GL_CONSTANT_ATTENUATION,1.0); glLightf(GL_LIGHT0,GL_LINEAR_ATTENUATION,0.1); glLightf(GL_LIGHT0,GL_QUADRATIC_ATTENUATION,0.01); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); } GLfloat mat_ambient[] = {0.5,0.5,0.5,1.0}; GLfloat mat_diffuse[] = {0.9,0.7,0.9,1.0}; GLfloat mat_specular[] = {0.8,0.8,0.8,1.0}; GLfloat mat_shininess[] = {100.0}; void do_material() { glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient); glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse); glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular); glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess); }