首先安裝PyOpengl
pip install PyOpenGL PyOpenGL_accelerate
64bit下可能存在glut的問題,解決如下
下載地址:(選擇適合自己的版本)http://www.lfd.uci.edu/~gohlke/pythonlibs/#pyopengl
下載下來的whl文件,用pip install file_name.whl進行安裝后,問題解決。
在Ubuntu環境下
sudo apt-get install python-opengl
項目效果
程序框架簡介:
primitive 負責具體渲染的模型,主要是生成顯示列表
G_OBJ_PLANE = 1
G_OBJ_SPHERE = 2
G_OBJ_CUBE = 3
這些模型會在程序初始化的時候運行一次 Viewer的init函數中。
主框架是Viewer文件
MainLoop 里面定時調用這里注冊的render函數
render 每次設置好MV矩陣,調用scene里面的render
Scene本身是一個節點的列表。每個節點會調用相應的顯示列表來渲染。
代碼Viewer.py
# -*- coding: utf8 -*- from OpenGL.GL import glCallList, glClear, glClearColor, glColorMaterial, glCullFace, glDepthFunc, glDisable, glEnable,\ glFlush, glGetFloatv, glLightfv, glLoadIdentity, glMatrixMode, glMultMatrixf, glPopMatrix, \ glPushMatrix, glTranslated, glViewport, \ GL_AMBIENT_AND_DIFFUSE, GL_BACK, GL_CULL_FACE, GL_COLOR_BUFFER_BIT, GL_COLOR_MATERIAL, \ GL_DEPTH_BUFFER_BIT, GL_DEPTH_TEST, GL_FRONT_AND_BACK, GL_LESS, GL_LIGHT0, GL_LIGHTING, \ GL_MODELVIEW, GL_MODELVIEW_MATRIX, GL_POSITION, GL_PROJECTION, GL_SPOT_DIRECTION from OpenGL.constants import GLfloat_3, GLfloat_4 from OpenGL.GLU import gluPerspective, gluUnProject from OpenGL.GLUT import glutCreateWindow, glutDisplayFunc, glutGet, glutInit, glutInitDisplayMode, \ glutInitWindowSize, glutMainLoop, \ GLUT_SINGLE, GLUT_RGB, GLUT_WINDOW_HEIGHT, GLUT_WINDOW_WIDTH import numpy from numpy.linalg import norm, inv from primitive import init_primitives from Scene import Scene from node import Sphere from node import SnowFigure,Cube,Plane class Viewer(object): def __init__(self): """ Initialize the viewer. """ #初始化接口,創建窗口並注冊渲染函數 self.init_interface() #初始化opengl的配置 self.init_opengl() #初始化3d場景 self.init_scene() #初始化交互操作相關的代碼 self.init_interaction() init_primitives() def init_interface(self): """ 初始化窗口並注冊渲染函數 """ glutInit() glutInitWindowSize(640, 480) glutCreateWindow("3D Modeller") glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB) #注冊窗口渲染函數 glutDisplayFunc(self.render) def init_opengl(self): """ 初始化opengl的配置 """ #模型視圖矩陣 self.inverseModelView = numpy.identity(4) #模型視圖矩陣的逆矩陣 self.modelView = numpy.identity(4) #開啟剔除操作效果 glEnable(GL_CULL_FACE) #取消對多邊形背面進行渲染的計算(看不到的部分不渲染) glCullFace(GL_BACK) #開啟深度測試 glEnable(GL_DEPTH_TEST) #測試是否被遮擋,被遮擋的物體不予渲染 glDepthFunc(GL_LESS) #啟用0號光源 glEnable(GL_LIGHT0) #設置光源的位置 glLightfv(GL_LIGHT0, GL_POSITION, GLfloat_4(0, 0, 1, 0)) #設置光源的照射方向 glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, GLfloat_3(0, 0, -1)) #設置材質顏色 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE) glEnable(GL_COLOR_MATERIAL) #設置清屏的顏色 glClearColor(0.4, 0.4, 0.4, 0.0) def init_scene(self): #初始化場景,之后實現 # 創建一個場景實例 self.scene = Scene() # 初始化場景內的對象 self.create_sample_scene() def create_sample_scene(self): # 創建一個球體 sphere_node = Sphere() # 設置球體的顏色 sphere_node.color_index = 2 # 將球體放進場景中,默認在正中央 sphere_node.translate(2, 2, 0) sphere_node.scale(4) self.scene.add_node(sphere_node) # 添加小雪人 hierarchical_node = SnowFigure() hierarchical_node.translate(-2, 0, -2) hierarchical_node.scale(2) self.scene.add_node(hierarchical_node) #添加立方體 cube_node=Cube() cube_node.color_index=5 cube_node.translate(5,5,0) cube_node.scale(1.8) self.scene.add_node(cube_node) #添加Plane plane_node=Plane() plane_node.color_index=2 self.scene.add_node(plane_node) def init_interaction(self): #初始化交互操作相關的代碼,之后實現 pass def main_loop(self): #程序主循環開始 glutMainLoop() def render(self): #程序進入主循環后每一次循環調用的渲染函數 # 初始化投影矩陣 self.init_view() # 啟動光照 glEnable(GL_LIGHTING) # 清空顏色緩存與深度緩存 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 設置模型視圖矩陣,目前為止用單位矩陣就行了。 glMatrixMode(GL_MODELVIEW) glPushMatrix() glLoadIdentity() # 渲染場景 self.scene.render() # 每次渲染后復位光照狀態 glDisable(GL_LIGHTING) glPopMatrix() # 把數據刷新到顯存上 glFlush() def init_view(self): """ 初始化投影矩陣 """ xSize, ySize = glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT) #得到屏幕寬高比 aspect_ratio = float(xSize) / float(ySize) #設置投影矩陣 glMatrixMode(GL_PROJECTION) glLoadIdentity() #設置視口,應與窗口重合 glViewport(0, 0, xSize, ySize) #設置透視,攝像機上下視野幅度70度 #視野范圍到距離攝像機1000個單位為止。 gluPerspective(70, aspect_ratio, 0.1, 1000.0) #攝像機鏡頭從原點后退15個單位 glTranslated(0, 0, -15) if __name__ == "__main__": viewer = Viewer() viewer.main_loop()
Scene.py
# -*- coding: utf8 -*- class Scene(object): #放置節點的深度,放置的節點距離攝像機15個單位 PLACE_DEPTH = 15.0 def __init__(self): #場景下的節點隊列 self.node_list = list() def add_node(self, node): """ 在場景中加入一個新節點 """ self.node_list.append(node) def render(self): """ 遍歷場景下所有節點並渲染 """ for node in self.node_list: node.render()
color.py
# -*- coding: utf8 -*- MAX_COLOR = 9 MIN_COLOR = 0 COLORS = { # RGB Colors 0: (1.0, 1.0, 1.0), 1: (0.05, 0.05, 0.9), 2: (0.05, 0.9, 0.05), 3: (0.9, 0.05, 0.05), 4: (0.9, 0.9, 0.0), 5: (0.1, 0.8, 0.7), 6: (0.7, 0.2, 0.7), 7: (0.7, 0.7, 0.7), 8: (0.4, 0.4, 0.4), 9: (0.0, 0.0, 0.0), }
node.py
# -*- coding: utf8 -*- import random from OpenGL.GL import glCallList, glColor3f, glMaterialfv, glMultMatrixf, glPopMatrix, glPushMatrix, \ GL_EMISSION, GL_FRONT import numpy import color from primitive import G_OBJ_SPHERE,G_OBJ_CUBE,G_OBJ_PLANE from transform import scaling, translation class Node(object): def __init__(self): #該節點的顏色序號 self.color_index = random.randint(color.MIN_COLOR, color.MAX_COLOR) #該節點的平移矩陣,決定了該節點在場景中的位置 self.translation_matrix = numpy.identity(4) #該節點的縮放矩陣,決定了該節點的大小 self.scaling_matrix = numpy.identity(4) def render(self): """ 渲染節點 """ glPushMatrix() #實現平移 glMultMatrixf(numpy.transpose(self.translation_matrix)) #實現縮放 glMultMatrixf(self.scaling_matrix) cur_color = color.COLORS[self.color_index] #設置顏色 glColor3f(cur_color[0], cur_color[1], cur_color[2]) #渲染對象模型 self.render_self() glPopMatrix() def render_self(self): raise NotImplementedError( "The Abstract Node Class doesn't define 'render_self'") def translate(self, x, y, z): self.translation_matrix = numpy.dot(self.translation_matrix, translation([x, y, z])) def scale(self, s): self.scaling_matrix = numpy.dot(self.scaling_matrix, scaling([s,s,s])) class Primitive(Node): def __init__(self): super(Primitive, self).__init__() self.call_list = None def render_self(self): glCallList(self.call_list) class Sphere(Primitive): """ 球形圖元 """ def __init__(self): super(Sphere, self).__init__() self.call_list = G_OBJ_SPHERE class Cube(Primitive): """ 立方體圖元 """ def __init__(self): super(Cube, self).__init__() self.call_list = G_OBJ_CUBE class Plane(Primitive): def __init__(self): super(Plane,self).__init__() self.call_list=G_OBJ_PLANE class HierarchicalNode(Node): def __init__(self): super(HierarchicalNode, self).__init__() self.child_nodes = [] def render_self(self): for child in self.child_nodes: child.render() class SnowFigure(HierarchicalNode): def __init__(self): super(SnowFigure, self).__init__() self.child_nodes = [Sphere(), Sphere(), Sphere()] self.child_nodes[0].translate(0, -0.6, 0) self.child_nodes[1].translate(0, 0.1, 0) self.child_nodes[1].scale(0.8) self.child_nodes[2].translate(0, 0.75, 0) self.child_nodes[2].scale(0.7) for child_node in self.child_nodes: child_node.color_index = color.MIN_COLOR
transform.py
# -*- coding: utf8 -*- import numpy def translation(displacement): """ 生成平移矩陣 """ t = numpy.identity(4) t[0, 3] = displacement[0] t[1, 3] = displacement[1] t[2, 3] = displacement[2] return t def scaling(scale): """ 生成縮放矩陣 """ s = numpy.identity(4) s[0, 0] = scale[0] s[1, 1] = scale[1] s[2, 2] = scale[2] s[3, 3] = 1 return s
primitive.py
# -*- coding: utf8 -*- from OpenGL.GL import glBegin, glColor3f, glEnd, glEndList, glLineWidth, glNewList, glNormal3f, glVertex3f, \ GL_COMPILE, GL_LINES, GL_QUADS from OpenGL.GLU import gluDeleteQuadric, gluNewQuadric, gluSphere G_OBJ_PLANE = 1 G_OBJ_SPHERE = 2 G_OBJ_CUBE = 3 def make_plane(): glNewList(G_OBJ_PLANE, GL_COMPILE) glBegin(GL_LINES) glColor3f(0, 0, 0) for i in xrange(41): glVertex3f(-10.0 + 0.5 * i, 0, -10) glVertex3f(-10.0 + 0.5 * i, 0, 10) glVertex3f(-10.0, 0, -10 + 0.5 * i) glVertex3f(10.0, 0, -10 + 0.5 * i) # Axes glEnd() glLineWidth(5) glBegin(GL_LINES) glColor3f(0.5, 0.7, 0.5) glVertex3f(0.0, 0.0, 0.0) glVertex3f(5, 0.0, 0.0) glEnd() glBegin(GL_LINES) glColor3f(0.5, 0.7, 0.5) glVertex3f(0.0, 0.0, 0.0) glVertex3f(0.0, 5, 0.0) glEnd() glBegin(GL_LINES) glColor3f(0.5, 0.7, 0.5) glVertex3f(0.0, 0.0, 0.0) glVertex3f(0.0, 0.0, 5) glEnd() # Draw the Y. glBegin(GL_LINES) glColor3f(0.0, 0.0, 0.0) glVertex3f(0.0, 5.0, 0.0) glVertex3f(0.0, 5.5, 0.0) glVertex3f(0.0, 5.5, 0.0) glVertex3f(-0.5, 6.0, 0.0) glVertex3f(0.0, 5.5, 0.0) glVertex3f(0.5, 6.0, 0.0) # Draw the Z. glVertex3f(-0.5, 0.0, 5.0) glVertex3f(0.5, 0.0, 5.0) glVertex3f(0.5, 0.0, 5.0) glVertex3f(-0.5, 0.0, 6.0) glVertex3f(-0.5, 0.0, 6.0) glVertex3f(0.5, 0.0, 6.0) # Draw the X. glVertex3f(5.0, 0.0, 0.5) glVertex3f(6.0, 0.0, -0.5) glVertex3f(5.0, 0.0, -0.5) glVertex3f(6.0, 0.0, 0.5) glEnd() glLineWidth(1) glEndList() def make_sphere(): """ 創建球形的渲染函數列表 """ glNewList(G_OBJ_SPHERE, GL_COMPILE) quad = gluNewQuadric() gluSphere(quad, 0.5, 30, 30) gluDeleteQuadric(quad) glEndList() def make_cube(): glNewList(G_OBJ_CUBE, GL_COMPILE) vertices = [((-0.5, -0.5, -0.5), (-0.5, -0.5, 0.5), (-0.5, 0.5, 0.5), (-0.5, 0.5, -0.5)), ((-0.5, -0.5, -0.5), (-0.5, 0.5, -0.5), (0.5, 0.5, -0.5), (0.5, -0.5, -0.5)), ((0.5, -0.5, -0.5), (0.5, 0.5, -0.5), (0.5, 0.5, 0.5), (0.5, -0.5, 0.5)), ((-0.5, -0.5, 0.5), (0.5, -0.5, 0.5), (0.5, 0.5, 0.5), (-0.5, 0.5, 0.5)), ((-0.5, -0.5, 0.5), (-0.5, -0.5, -0.5), (0.5, -0.5, -0.5), (0.5, -0.5, 0.5)), ((-0.5, 0.5, -0.5), (-0.5, 0.5, 0.5), (0.5, 0.5, 0.5), (0.5, 0.5, -0.5))] normals = [(-1.0, 0.0, 0.0), (0.0, 0.0, -1.0), (1.0, 0.0, 0.0), (0.0, 0.0, 1.0), (0.0, -1.0, 0.0), (0.0, 1.0, 0.0)] glBegin(GL_QUADS) for i in xrange(6): glNormal3f(normals[i][0], normals[i][1], normals[i][2]) for j in xrange(4): glVertex3f(vertices[i][j][0], vertices[i][j][1], vertices[i][j][2]) glEnd() glEndList() def init_primitives(): """ 初始化所有的圖元渲染函數列表 """ make_plane() make_sphere() make_cube()