
算法机制
?
如上图所示,实现的是地球(绿色)围绕太阳(红色)公转,月亮(黄色)围绕地球转,同时地球也在自转的动画。具体原理如下:
?
首先初始化一块画布,开启深度测试,虽然当下视角看不到遮盖效果,但是在改变观测视角的情况下,还是有必要开启深度测试,避免天体之间的前后关系混乱。
利用到了openGL里的glMatrixMode(GL_PROJECTION)函数将矩阵设置成投影模式,满足绘图所需执行的矩阵变换,glLoadIdentity()函数将当前矩阵设为单位矩阵,因为在变换前需要将矩阵设置为单位矩阵,也用到了gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear,GLdouble zFar)透视投影的函数来设置 眼睛上下睁开的幅度 、实际窗口的横纵比、 近截面和远截面。以及glMatrixMode(GL_MODELVIEW)将矩阵设置成视图模式,满足绘图所需执行的矩阵变换。gluLookAt()来设置观测点坐标,观测物体坐标,以及观测方向。
在绘图函数draw()里,我定义一个全局变量day,来控制地球绕太阳旋转的角度,以及月亮绕地球旋转的角度,以及控制地球自转。太阳,地球和月亮是利用OpenGL里自带的画球函数glutWireSphere来绘制的。通过glRotatef()函数来设置天体绕中心天体旋转的角度,以及绕天体运动的轴,我选择的是都绕Z轴正方向旋转。glTranslatef()来使绘制的天体按设置的方向和距离平移。
在main函数里,首先令变量day=100,然后每次调用draw函数时,变量day都加一,day大于等于360时,重新设置为零,通过不断的绘制图形以此来实现天体动态运动的效果。然而即使开启双缓冲区,即glutSwapBuffers()函数,我发现天体运动的速度还是过快,最后只好使用time.sleep()函数,来强制限制图形绘制显示的速度,最后实验效果较为理想。
代码
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.raw.GLU import *
import time
def init():
??? glEnable(GL_DEPTH_TEST)
??? glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
??? glViewport(0, 0, 200, 200)? # 定义视区大小
??? glMatrixMode(GL_PROJECTION)
??? glLoadIdentity()
??? gluPerspective(60, 100 / 100, 1, 20)
??? glMatrixMode(GL_MODELVIEW)
??? glLoadIdentity()
??? gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
def draw():
??? global day
??? day = day + 1
??? if day >= 360:
??????? day = 0
??? glEnable(GL_DEPTH_TEST)
??? glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
??? # 太阳
??? glPushMatrix()
??? glColor3f(1.0, 0.0, 0.0)
??? glutWireSphere(1.0, 20, 16)
??? # 地球
??? glRotatef(day, 0.0, 0.0, 1.0)
??? glTranslatef(2.0, 0.0, 0.0)
??? glRotatef(day / 1 * 360, 0.0, 0.0, 1.0)
??? glPushMatrix()
??? glMatrixMode(GL_MODELVIEW)
??? glRotatef(60.0, 0.0, 1.0, 1.0)
??? glColor3f(0.0, 1.0, 0.0)
??? glutWireSphere(0.2, 10, 8)
??? glPopMatrix()
??? # 月亮
??? glRotatef(day / 30 * 360, 0.0, 0.0, 1.0)
??? glTranslatef(0.4, 0.0, 0.0)
??? glColor3f(1.0, 1.0, 0.0)
??? glutWireSphere(0.05, 10, 8)
??? glPopMatrix()
??? glutSwapBuffers()
??? glFlush
??? time.sleep(0.05)
if __name__ == "__main__":
??? day = 100
??? glutInit()? # 1. 初始化glut库
??? glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DOUBLE | GLUT_DOUBLE)
??? glutInitWindowPosition(100, 100)
??? glutInitWindowSize(400, 400)
??? glutCreateWindow("run")
??? init()
??? glutDisplayFunc(draw)? # 3. 注册回调函数draw()
??? glutIdleFunc(draw)
??? glutMainLoop()
|