// ------------------------------------------------------------------------ // This program is complementary material for the book: // // Frank Nielsen // // Visual Computing: Geometry, Graphics, and Vision // // ISBN: 1-58450-427-7 // // Charles River Media, Inc. // // // All programs are available at http://www.charlesriver.com/visualcomputing/ // // You may use this program for ACADEMIC and PERSONAL purposes ONLY. // // // The use of this program in a commercial product requires EXPLICITLY // written permission from the author. The author is NOT responsible or // liable for damage or loss that may be caused by the use of this program. // // Copyright (c) 2005. Frank Nielsen. All rights reserved. // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ // File: spheresubdivision.cpp // // Description: subdivision refinement of the icosahedron for approximating // the unit sphere // ------------------------------------------------------------------------ #include "stdafx.h" #include #include #include using namespace std; // coordinates of one of the icosahedron vertex #define X 0.525731112119133696 #define Z 0.850650808352039932 // icosahedron vertices static GLfloat icosahedronvertex[12][3] = { {-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z}, {0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X}, {Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0} }; // icosehedron faces static int icosahedrontriangle[20][3] = { {1,4,0}, {4,9,0}, {4,5,9}, {8,5,4}, {1,8,4}, {1,10,8}, {10,3,8}, {8,3,5}, {3,2,5}, {3,7,2}, {3,10,7}, {10,6,7}, {6,11,7}, {6,0,11}, {6,1,0}, {10,1,6}, {11,0,9}, {2,11,9}, {5,2,9}, {11,2,7} }; GLfloat angle=0.0; int subdiv = 0; bool animation=true; // Vertices should belong to the unit sphere. // so we perform normalization void Normalize(GLfloat v[3]) { GLfloat d = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); if (d!=0.0) { v[0]/=d; v[1]/=d; v[2]/=d; } } // Recursively subdivide the sphere void OneToFourTriangle(GLfloat v1[3], GLfloat v2[3], GLfloat v3[3], int depth) { GLfloat v12[3], v23[3], v31[3]; int i; if (depth == 0) { Normalize(v1); Normalize(v2); Normalize(v3); glColor3f(0.5,0.5,0.5); glBegin(GL_TRIANGLES); glVertex3fv(v1); glVertex3fv(v2); glVertex3fv(v3); glEnd(); glColor3f(0,0,0); glLineWidth(3); glBegin(GL_LINE_LOOP); glVertex3fv(v1); glVertex3fv(v2); glVertex3fv(v3); glEnd(); } else { // midpoint for (i = 0; i < 3; i++) { v12[i] = (v1[i]+v2[i])/2.0; v23[i] = (v2[i]+v3[i])/2.0; v31[i] = (v3[i]+v1[i])/2.0; } // lift midpoints on the sphere Normalize(v12); Normalize(v23); Normalize(v31); // subdivide new one-to-four triangles OneToFourTriangle(v1, v12, v31, depth-1); OneToFourTriangle(v2, v23, v12, depth-1); OneToFourTriangle(v3, v31, v23, depth-1); OneToFourTriangle(v12, v23, v31, depth-1); } } void display(void) { int i; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.5, 0.5, -1.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); if (animation) angle+=0.3; if (angle>360) angle-=360.0; glPushMatrix(); glRotatef(angle,1,0,1); // subdivide each face of the triangle for (i = 0; i < 20; i++) { OneToFourTriangle(&icosahedronvertex[icosahedrontriangle[i][0]][0], &icosahedronvertex[icosahedrontriangle[i][1]][0], &icosahedronvertex[icosahedrontriangle[i][2]][0], subdiv); } glPopMatrix(); glFlush(); glutSwapBuffers(); } void reshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.25, 1.25, -1.25 , 1.25 , -2.0, 2.0); glMatrixMode(GL_MODELVIEW); glutPostRedisplay(); } void keyboard(unsigned char key, int x, int y) { if (key=='q') exit(0); if (key==' ') { animation=!animation; } if (key=='+') subdiv++; if (key=='-') { subdiv--; if (subdiv<0) subdiv = 0; } glutPostRedisplay(); } void idle() { if (animation) subdiv=(int)(angle/70); glutPostRedisplay(); } int main(int argc, char **argv) { cout<<"Visual Computing: Geometry, Graphics, and Vision (ISBN:1-58450-427-7)"<