import sys, time from math import * from OpenGL.GL import * from OpenGL.GLU import * from OpenGL.GLUT import * class keyframe: def __init__(self, t): self.time = t self.tx = 0 self.ty = 0 self.tz = 0 def lerp(a,b,frac): return a + (b-a)*frac def catmullRom(p0, p1, p2, p3, frac): c3 = -0.5*p0 + 1.5*p1 - 1.5*p2 + 0.5*p3 c2 = p0 - 2.5*p1 + 2*p2 - 0.5*p3 c1 = -0.5*p0 + 0.5 * p2 c0 = p1 return c3 * frac*frac*frac + c2 * frac*frac + c1 * frac + c0 class keyframeAnimation: def __init__(self, keyfile): self.keys = [] for line in open(keyfile): parts = line.split() if len(parts) < 4: continue k = keyframe(float(parts[0])) k.tx = float(parts[1]) k.ty = float(parts[2]) k.tz = float(parts[3]) self.keys.append(k) def applyLinear(self, t): first = 0 while (first+1 < len(self.keys)) and (self.keys[first+1].time <= t): first += 1 if first+1 == len(self.keys): first -= 1 frac = 1 else: frac = float(t - self.keys[first].time) / (self.keys[first+1].time - self.keys[first].time) if frac < 0: frac = 0 x = lerp(self.keys[first].tx, self.keys[first+1].tx, frac) y = lerp(self.keys[first].ty, self.keys[first+1].ty, frac) z = lerp(self.keys[first].tz, self.keys[first+1].tz, frac) glTranslatef(x,y,z) def computeSpline(self, t): first = 0 while (first+1 < len(self.keys)) and (self.keys[first+1].time <= t): first += 1 if first+1 == len(self.keys): first -= 1 frac = 1 else: frac = float(t - self.keys[first].time) / (self.keys[first+1].time - self.keys[first].time) if frac < 0: frac = 0 if first == 0: key0 = self.keys[0] else: key0 = self.keys[first-1] key1 = self.keys[first] key2 = self.keys[first+1] if first > len(self.keys)-3: key3 = self.keys[first+1] else: key3 = self.keys[first+2] x = catmullRom(key0.tx, key1.tx, key2.tx, key3.tx, frac) y = catmullRom(key0.ty, key1.ty, key2.ty, key3.ty, frac) z = catmullRom(key0.tz, key1.tz, key2.tz, key3.tz, frac) return x,y,z def applySpline(self, t): x, y, z = self.computeSpline(t) glTranslatef(x,y,z) viewRotX = 30 viewRotY = 0 viewDistance = 30 def draw(): glClearColor(0.5, 0.8, 1, 0.0) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glEnable(GL_DEPTH_TEST) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(50.0, 1.33, 1.0, 100.0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glTranslatef(0.0, 0.0, -viewDistance) glRotatef(viewRotX, 1.0, 0.0, 0.0) glRotatef(viewRotY, 0.0, 1.0, 0.0) defineLight() glEnable(GL_LIGHTING) global floorMeshDList glCallList(floorMeshDList) drawTeapot() drawPedestal() drawBall() glDisable(GL_LIGHTING) glutSwapBuffers() def defineLight(): glEnable(GL_LIGHT0) glLightfv(GL_LIGHT0, GL_DIFFUSE, [1, 1, 1, 1]) glLightfv(GL_LIGHT0, GL_POSITION, [-1, 2, 1, 0]) def drawFloorMesh(columns,rows): green = [ 0, 0.8, 0.1, 1 ] black = [ 0, 0, 0, 1 ] glMaterialfv(GL_FRONT, GL_AMBIENT, green) glMaterialfv(GL_FRONT, GL_DIFFUSE, green) glMaterialfv(GL_FRONT, GL_SPECULAR, black) glNormal3f(0.0, 1.0, 0.0) for j in range(0,rows): glBegin(GL_TRIANGLE_STRIP) for i in range(0,columns): x = ((float(i)) / columns) * 40.0 - 20.0 z = ((float(j)) / rows) * 40.0 - 20.0 glVertex3f(x, -2.0, z) z = ((float(j)+1) / rows) * 40.0 - 20.0 glVertex3f(x, -2.0, z) glEnd() def drawTeapot(): red = [ 0.8, 0, 0, 1 ] white = [ 1, 1, 1, 1 ] glMaterialfv(GL_FRONT, GL_AMBIENT, red) glMaterialfv(GL_FRONT, GL_DIFFUSE, red) glMaterialfv(GL_FRONT, GL_SPECULAR, white) glMaterialf(GL_FRONT, GL_SHININESS, 90.0) glPushMatrix() glTranslatef(2.0, 4.0, -1.0) glRotatef(currentTime() * 30.0, 0.0, 1.0, 0.0) global teapotDList glCallList(teapotDList) glPopMatrix() quadric = None def drawPedestal(): global quadric grey = [ 0.6, 0.6, 0.6, 1 ] white = [ 1, 1, 1, 1 ] if not quadric: quadric = gluNewQuadric() glMaterialfv(GL_FRONT, GL_AMBIENT, grey) glMaterialfv(GL_FRONT, GL_DIFFUSE, grey) glMaterialfv(GL_FRONT, GL_SPECULAR, white) glMaterialf(GL_FRONT, GL_SHININESS, 30.0) glPushMatrix() glTranslatef(2.0, -2.0, -1.0) glRotatef(-90.0, 1.0, 0.0, 0.0) gluCylinder(quadric, 4.0, 4.0, 4.0, 16, 1) glTranslatef(0.0, 0.0, 4.0) gluDisk(quadric, 0.0, 4.0, 16, 1) glPopMatrix() ballAnim = keyframeAnimation('ballkeys.txt') def drawBall(): cyan = [ 0, 1, 1, 1 ] black = [ 0, 0, 0, 1 ] glMaterialfv(GL_FRONT, GL_AMBIENT, cyan) glMaterialfv(GL_FRONT, GL_DIFFUSE, cyan) glMaterialfv(GL_FRONT, GL_SPECULAR, black) glPushMatrix() ballAnim.applySpline(currentTime()) glutSolidSphere(2.0, 16, 8) glPopMatrix() glBegin(GL_LINE_STRIP) for i in range(0,101): glVertex3fv(ballAnim.computeSpline(i*10.0/100)) glEnd() startTime = time.time() def currentTime(): return time.time() - startTime def keyboard(key, x, y): global viewDistance if key == chr(27): sys.exit(0) elif key == '.': viewDistance -= 1 elif key == ',': viewDistance += 1 def specialkey(k, x, y): global viewRotX, viewRotY if k == GLUT_KEY_LEFT: viewRotY += 3 elif k == GLUT_KEY_RIGHT: viewRotY -= 3 elif k == GLUT_KEY_UP: viewRotX += 3 elif k == GLUT_KEY_DOWN: viewRotX -= 3 glutInit([]) glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH) glutInitWindowSize(800,600) glutCreateWindow(sys.argv[0]) glutDisplayFunc(draw) glutKeyboardFunc(keyboard) glutSpecialFunc(specialkey) glutIdleFunc(glutPostRedisplay) glEnable(GL_DEPTH_TEST) glEnable(GL_LIGHTING) glEnable(GL_LIGHT0) floorMeshDList = glGenLists(1) glNewList(floorMeshDList, GL_COMPILE) drawFloorMesh(32,32) glEndList() teapotDList = glGenLists(1) glNewList(teapotDList, GL_COMPILE) glutSolidTeapot(2) glEndList() glutMainLoop()