/* Demo of how the front and back of quadilaterals look using material and lighting. The result shows that if you use one-sided quads and you don't use backface culling, the front and back are drawn using exactly the same color, which seems weird if you're thinking about where the light is coming from and the effect of diffuse and specular terms. To get the effect that you want (defined as the same colors as a sphere), you have to use two-sided drawing, and specify a back material, even if it's the same as the front material. It seems like you wouldn't have to, since all the facets of a sphere are front material, right? Summary: to get facets that look like a sphere, you need: backface culling off (default) two-sided light model (default is false) two-sided material OR backface culling irrelevant one-sided light model (irrelevant, since we never see the back) one-sided material draw both sides of a quad but in the latter case, you have to have some space between them, or the depth buffer will get confused and you'll only see the one you draw second, I think. However, getting that distance correct is very hard. So the latter approach doesn't really work. If you want 2D planes (not 3D things like glutSolidCube), you need to use the first approach. Implemented Fall 2004 Scott D. Anderson */ #include #include #include twTriple Quad[4] = { {0,0,0}, // left, bottom, front {1,0,0}, // right, bottom, front {1,1,0}, // left, top, front {0,1,0}, // right, top, front }; bool CullFace = false; bool Amb = true; bool Diff = true; bool Spec = true; bool LocalViewer = false; bool TwoSided = true; // use back materials void drawQuad(int a, int b, int c, int d) { twTriple N; twPlaneNormal(N,Quad[a],Quad[b],Quad[c]); glNormal3f(N[0],N[1],N[2]); // twTriplePrint("N=",N); glBegin(GL_QUADS); glVertex3fv(Quad[a]); glVertex3fv(Quad[b]); glVertex3fv(Quad[c]); glVertex3fv(Quad[d]); glEnd(); } void display(void) { twDisplayInit(); twCamera(); if(CullFace) { glEnable(GL_CULL_FACE); } else { glDisable(GL_CULL_FACE); } glEnable(GL_NORMALIZE); GLfloat lightDir[] = { -1, 0, 1, 0}; // from back right twGrayLight(GL_LIGHT0,lightDir,0.3,0.5,0.7); glEnable(GL_LIGHTING); if(LocalViewer) { glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,1); } else { glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,0); } if(TwoSided) { glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,1); } else { glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0); } const float d = 255.0; twTriple salmon = {255/d,128/d,114/d}; twTriple white = {1,1,1}; twTriple black = {0,0,0}; twTriple red = {1,0,0}; twTriple green = {0,1,0}; twTriple blue = {0,0,1}; twTriple yellow50 = {0.5,0.5,0}; twTriple cyan50 = {0,0.5,0.5}; twTriple magenta50 = {0.5,0,0.5}; glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,Amb?salmon:black); glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,Diff?salmon:black); glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,Spec?white:black); glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,10); glutSolidSphere(1,32,32); // Upper right quads face front glPushMatrix(); glTranslatef(+1,+1,0); drawQuad(0,1,2,3); glTranslatef(1,0,0); glRotatef(-10,0,1,0); drawQuad(0,1,2,3); glPopMatrix(); // upper left attempts to show what it looks like from the back glPushMatrix(); glTranslatef(-1,+1,0); glRotatef(180,0,1,0); drawQuad(0,1,2,3); glTranslatef(1,0,0); glRotatef(-10,0,1,0); drawQuad(0,1,2,3); glPopMatrix(); // lower right quad draws both sides of each quad glPushMatrix(); glTranslatef(+1,-1,0); drawQuad(0,1,2,3); glTranslatef(0,0,-1); drawQuad(0,3,2,1); glTranslatef(1,0,+1); glRotatef(-10,0,1,0); drawQuad(0,1,2,3); glTranslatef(0,0,-1); drawQuad(0,3,2,1); glPopMatrix(); glFlush(); glutSwapBuffers(); } void keys(unsigned char k, int x, int y) { switch(k) { case 'a': Amb = !Amb; break; case 'd': Diff = !Diff; break; case 's': Spec = !Spec; break; case 'c': CullFace = !CullFace; break; case '1': { twTriple Y={0,1,0}; twRotateViewpoint(180,Y); } break; case 'l': LocalViewer = !LocalViewer; break; case '2': TwoSided = !TwoSided; break; case 'p': printf("\nAmbient %s\nDiffuse %s\nSpecular %s\nCullFace %s\nLocalViewer %s\nTwoSided %s\n", Amb?"on":"off", Diff?"on":"off", Spec?"on":"off", CullFace?"on":"off", LocalViewer?"on":"off", TwoSided?"on":"off"); break; } glutPostRedisplay(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); twInitWindowSize(500,500); glutCreateWindow(argv[0]); glutDisplayFunc(display); twBoundingBox(-2,+2,-2,+2,-1,+1); // a lie twMainInit(); twKeyCallback('c',keys,"toggle backface culling"); twKeyCallback('a',keys,"toggle Ambient = red"); twKeyCallback('d',keys,"toggle Diffuse = green"); twKeyCallback('s',keys,"toggle Specular = blue"); twKeyCallback('1',keys,"180 degree rotation"); twKeyCallback('2',keys,"toggle two-sided lighting"); twKeyCallback('l',keys,"toggle local viewer"); twKeyCallback('p',keys,"print settings"); glutMainLoop(); return 0; }