topical media & game development
basic-visual-05-spheresubdivision.c
? /
basic-visual-05-spheresubdivision.c
// ------------------------------------------------------------------------
// 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 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 <stdlib.h>
include <math.h>
include <GL/glut.h>
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)"<<endl;
cout<<"Demo program\n\n"<<endl;
cout<<"Recursive subdivision of the icosahedron for approximating the sphere."<<endl;
cout<<"' ' SPACE: toggle on/off animation."<<endl;
cout<<"+/- increase/decrease subdivision level."<<endl;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(1024,1024);
glutCreateWindow("Icosahedron subdivision for approximating the sphere");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutIdleFunc(idle);
glClearColor(1.0, 1.0, 1.0, 0.0);
glEnable(GL_DEPTH_TEST);
glutMainLoop();
return(0);
}
(C) Æliens
20/2/2008
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.