// Computergrafik I // Prof. Dr. Juergen Doellner // Sommersemester 2001 // // Programmrahmen fuer Aufgabe 4 // Stephan Brumme, 702544 // last changes: May 07, 2001 // ---------------------------------------------------------- // It might be useful to use the class "Vector" presented in // the exercises // ---------------------------------------------------------- #include "cgsphere.h" #include CGSphere::CGSphere() { // adjust to fit the window m_fRadius = 0.95; m_nTessellationLevel = 6; m_bUseFlatShade = true; m_bUseWireframe = false; m_bUseTriangleTessellation = true; } CGSphere::~CGSphere() { } void CGSphere::onInit() { // Set background color. glClearColor(0.4, 0.4, 0.7, 0); // blue // Set Shading if (m_bUseFlatShade) glShadeModel(GL_FLAT); else glShadeModel(GL_SMOOTH); // Enable Lighting GLfloat am[] = {0.5, 0.5, 0.5, 1.0}; GLfloat df[] = {1.0, 1.0, 1.0, 1.0}; GLfloat sp[] = {0.0, 0.0, 0.0, 1.0}; GLfloat pos[] = {1.0, 1.0, 0.0, 1.0}; glEnable(GL_LIGHTING); glLightfv(GL_LIGHT0, GL_AMBIENT, am); glLightfv(GL_LIGHT0, GL_DIFFUSE, df); glLightfv(GL_LIGHT0, GL_SPECULAR, sp); glLightfv(GL_LIGHT0, GL_POSITION, pos); glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.2); glEnable(GL_LIGHT0); // Let OpenGL compute normals automatically glEnable(GL_NORMALIZE); glEnable(GL_DEPTH_TEST); } void CGSphere::TessellateTriangle(const Vector& v1, const Vector& v2, const Vector& v3, int nLevel) { if (nLevel == 1) { // Dreieck zeichnen (eventuell als Drahtgittermodell) if (m_bUseWireframe) glBegin(GL_LINE_LOOP); else glBegin(GL_TRIANGLES); glVertex3f(v1[0], v1[1], v1[2]); glVertex3f(v2[0], v2[1], v2[2]); glVertex3f(v3[0], v3[1], v3[2]); glEnd(); } else { // Mittelpunkte der Seiten bestimmen Vector s1((v2[0]+v3[0])/2, (v2[1]+v3[1])/2, (v2[2]+v3[2])/2); Vector s2((v1[0]+v3[0])/2, (v1[1]+v3[1])/2, (v1[2]+v3[2])/2); Vector s3((v2[0]+v1[0])/2, (v2[1]+v1[1])/2, (v2[2]+v1[2])/2); // und normalisieren s1.normalize(); s2.normalize(); s3.normalize(); // weiter tessellieren TessellateTriangle(s1, s2, s3, nLevel-1); TessellateTriangle(v1, s3, s2, nLevel-1); TessellateTriangle(v2, s1, s3, nLevel-1); TessellateTriangle(v3, s1, s2, nLevel-1); } } void CGSphere::onDraw() { // Clear framebuffer using background color. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Set current color for drawing. glColor3f (1.0, 1.0, 1.0); // white glPushMatrix(); // Radius anpassen (da eigentlich nur Einheitskugel berechnet) glScalef (m_fRadius, m_fRadius, m_fRadius); // urgently needed ... const GLfloat fPi = 3.1415926; if (m_bUseTriangleTessellation) { // triangle tessellation // Eckpunkte festlegen const GLfloat fOffset = 1/sqrt(3); Vector v[4] = { Vector( fOffset, fOffset, fOffset), Vector(-fOffset,-fOffset, fOffset), Vector(-fOffset, fOffset,-fOffset), Vector( fOffset,-fOffset,-fOffset)}; // mit den 4 Seiten des Tetraeders die Tessellation beginnen TessellateTriangle(v[0], v[1], v[2], m_nTessellationLevel); TessellateTriangle(v[0], v[1], v[3], m_nTessellationLevel); TessellateTriangle(v[0], v[2], v[3], m_nTessellationLevel); TessellateTriangle(v[1], v[2], v[3], m_nTessellationLevel); } else { // quad tessellation // Winkelschrittweite const GLfloat fDeltaAlpha = fPi/m_nTessellationLevel; const GLfloat fDeltaBeta = 2*fPi/m_nTessellationLevel; // "Breitengrade" for (GLfloat fAlpha = -fPi/2; fAlpha < fPi/2; fAlpha += fDeltaAlpha) { // "Längengrade" for (GLfloat fBeta = 0; fBeta < 2*fPi; fBeta += fDeltaBeta) { // 4 Eckpunkte berechnen // Formeln in Aufgabe 3 erläutert Vector v1(cos(fAlpha)*sin(fBeta), sin(fAlpha), cos(fAlpha)*cos(fBeta)); Vector v2(cos(fAlpha+fDeltaAlpha)*sin(fBeta), sin(fAlpha+fDeltaAlpha), cos(fAlpha+fDeltaAlpha)*cos(fBeta)); Vector v3(cos(fAlpha+fDeltaAlpha)*sin(fBeta+fDeltaBeta), sin(fAlpha+fDeltaAlpha), cos(fAlpha+fDeltaAlpha)*cos(fBeta+fDeltaBeta)); Vector v4(cos(fAlpha)*sin(fBeta+fDeltaBeta), sin(fAlpha), cos(fAlpha)*cos(fBeta+fDeltaBeta)); // Viereck zeichnen (eventuell als Drahtgittermodell) if (m_bUseWireframe) glBegin(GL_LINE_LOOP); else glBegin(GL_QUADS); glVertex3f(v1[0], v1[1], v1[2]); glVertex3f(v2[0], v2[1], v2[2]); glVertex3f(v3[0], v3[1], v3[2]); glVertex3f(v4[0], v4[1], v4[2]); glEnd(); } } } glPopMatrix(); glFlush(); // Do not forget to swap front- and backbuffer! swapBuffers(); } void CGSphere::onKey(unsigned char key) { cout << key << endl; switch (key) { case 'q': exit(0); break; // Quit application. // Tessellationsgrad erhöhen case '+': m_nTessellationLevel++; cout << m_nTessellationLevel << endl; break; // Tessellationsgrad senken case '-': if (m_nTessellationLevel > 1) m_nTessellationLevel--; cout << m_nTessellationLevel << endl; break; // Rotationen rückgängig machen case 'r': glLoadIdentity(); break; // Shadingmodell umschalten flat/smooth case 's': m_bUseFlatShade = !m_bUseFlatShade; if (m_bUseFlatShade) glShadeModel(GL_FLAT); else glShadeModel(GL_SMOOTH); break; // Tessellationsmethode umschalten Dreieck/Viereck case 't': m_bUseTriangleTessellation = !m_bUseTriangleTessellation; break; // umschalten solid/Drahtgitter case 'w': m_bUseWireframe = !m_bUseWireframe; break; // um x-Achse drehen case 'x': glRotated(5, 1, 0, 0); break; case 'X': glRotated(-5, 1, 0, 0); break; // um y-Achse drehen case 'y': glRotated(5, 0, 1, 0); break; case 'Y': glRotated(-5, 0, 1, 0); break; // um z-Achse drehen case 'z': glRotated(5, 0, 0, 1); break; case 'Z': glRotated(-5, 0, 0, 1); break; } // Neuzeichnen erzwingen glutPostRedisplay(); } void CGSphere::onSize(int newWidth, int newHeight) { if((newWidth > 0) && (newHeight > 0)) { // Adjust OpenGL-Viewport according to new window dimensions. glViewport(0, 0, newWidth - 1, newHeight - 1); // Switch to modelview matrix stack and initialize // with identity matrix. glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } } // main program int main(int argc, char* argv[]) { // Generate an instance of the sample application. CGSphere* sample = new CGSphere(); // Starts the sample application. sample->start("CGSphere, Stephan Brumme, 702544"); return(0); }