/* 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 on one-sided light model (irrelevant, since we never see the back) one-sided material draw both sides of a quad The culling may be important, because if it's off (the default) the depth buffer may get confused and you'll only see the one you draw second, I think. This demo doesn't show that difficulty, but the OpenBox demo does. Implemented Fall 2004 Scott D. Anderson */ #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(); glPushAttrib(GL_ALL_ATTRIB_BITS); glDisable(GL_LIGHTING); glColor3f(0,0,1); twDrawString(Quad[a][0],Quad[a][1],Quad[a][2],"A"); twDrawString(Quad[b][0],Quad[b][1],Quad[b][2],"B"); twDrawString(Quad[c][0],Quad[c][1],Quad[c][2],"C"); twDrawString(Quad[d][0],Quad[d][1],Quad[d][2],"D"); glPopAttrib(); } 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.7,0.5); glEnable(GL_LIGHTING); if(LocalViewer) { glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,1); } else { glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,0); // OpenGL default is distant viewer } if(TwoSided) { glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,1); } else { glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,0); // OpenGL default is one-sided lighting } const float d = 255.0; twTriple salmon = {255/d,128/d,114/d}; twTriple white = {1,1,1}; twTriple black = {0,0,0}; 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); // 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,0); glRotatef(-10,0,1,0); drawQuad(0,1,2,3); // glTranslatef(0,0,-1); drawQuad(0,3,2,1); glPopMatrix(); // lower left is the sphere glPushMatrix(); glTranslatef(-1,-1,0); glutSolidSphere(1,32,32); glPopMatrix(); glPushAttrib(GL_ALL_ATTRIB_BITS); glDisable(GL_LIGHTING); glColor3f(0,0,1); twDrawString(+1,0.5,0,"facing light"); twDrawString(-3,0.5,0,"facing away"); twDrawString(+1,-1.5,0,"draw both sides"); twDrawString(0,-2.5,0,"TwoSide = %s",TwoSided?"on":"off"); twDrawString(0,-2.7,0,"CullFace = %s",CullFace?"on":"off"); twDrawString(0,-2.9,0,"LocalViewer = %s",LocalViewer?"on":"off"); twDrawString(0,-3.1,0,"Ambient = %s",Amb?"on":"off"); twDrawString(0,-3.3,0,"Diffuse = %s",Diff?"on":"off"); twDrawString(0,-3.5,0,"Specular = %s",Spec?"on":"off"); glPopAttrib(); 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 '0': { twTriple Y={0,1,0}; twRotateViewpoint(180,Y); } break; case 'l': LocalViewer = !LocalViewer; break; case '1': TwoSided = false; break; case '2': TwoSided = true; 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"); twKeyCallback('d',keys,"toggle Diffuse"); twKeyCallback('s',keys,"toggle Specular"); twKeyCallback('0',keys,"180-degree turn"); twKeyCallback('1',keys,"one-sided lighting"); twKeyCallback('2',keys,"two-sided lighting"); twKeyCallback('l',keys,"toggle local viewer"); twKeyCallback('p',keys,"print settings"); glutMainLoop(); return 0; }