首先安装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()

Python>>>创建一个简单的3D场景的更多相关文章

  1. Python创建一个简单的区块链

    区块链(Blockchain)是一种分布式账本(listributed ledger),它是一种仅供增加(append-only),内容不可变(immutable)的有序(ordered)链式数据结构 ...

  2. 基于python创建一个简单的HTTP-WEB服务器

    背景 大多数情况下主机资源只有开发和测试相关人员可以登录直接操作,且有些特定情况"答辩.演示.远程"等这些场景下是无法直接登录主机的.web是所有终端用户都可以访问了,解决了人员权 ...

  3. python创建一个简单的服务

    python -m http.server 8000 --bind 0.0.0.0 8000为端口 0.0.0.0允许远程访问

  4. 通过创建一个简单的骰子游戏来探究 Python

    在我的这系列的第一篇文章 中, 我已经讲解如何使用 Python 创建一个简单的.基于文本的骰子游戏.这次,我将展示如何使用 Python 模块 Pygame 来创建一个图形化游戏.它将需要几篇文章才 ...

  5. 使用Python创建一个简易的Web Server

    Python 2.x中自带了SimpleHTTPServer模块,到Python3.x中,该模块被合并到了http.server模块中.使用该模块,可以快速创建一个简易的Web服务器. 我们在C:\U ...

  6. Python框架学习之用Flask创建一个简单项目

    在前面一篇讲了如何创建一个虚拟环境,今天这一篇就来说说如何创建一个简单的Flask项目.关于Flask的具体介绍就不详细叙述了,我们只要知道它非常简洁.灵活和扩展性强就够了.它不像Django那样集成 ...

  7. Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏

    Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏 即使是如今,非常多初学游戏开发的同学.在谈到Unity的时候.依旧会觉得Unity仅仅能用于制作3D游戏的. 实际上.Unity在2013 ...

  8. 用django创建一个简单的sns

    用django创建一个简单的sns 1.首先创建一个工程newsns django-admin.py startproject newsns 在工程目录下新建一个文件夹templates,在该文件夹下 ...

  9. django创建一个简单的web站点

    一.新建project 使用Pycharm,File->New Project…,选择Django,给project命名 (project不能用test命名)   新建的project目录如下: ...

随机推荐

  1. kanboard邮件通知

    1. 复制config.default.php为config.php 2. 修改一下内容 define('MAIL_TRANSPORT', 'smtp');define('MAIL_SMTP_HOST ...

  2. 【python】操作excel——xlrd xlwt xlutils

    from xlutils.copy import copy import xlrd # import xlutils #打开已存在的excel rb=xlrd.open_workbook('D:\\1 ...

  3. MVC 支持同名路由,不同命名空间

    有时候我们会碰到两个项目合在一起,那么必然会碰到两个同名的controller,其实MVC在注册路由,添加Route的时候可以指定当前规则解析那个命名空间下的所有Controller. 注:Contr ...

  4. Tabbed Activity的使用(Fragment)

    1,首先file -> new -> Activity -> Tabbed Activity 2,创建完成后,发现会自动的创建一大堆代码,大部分我们是不需要关心的,关于页面切换的代码 ...

  5. ansible安装httpd

    --- - hosts: web   tasks:       - name: "INSTALL"         yum: name={{ item  }} state=pres ...

  6. 如何启动一个Java Web应用

    最近使用一个开源项目写程序,为了方便沟通加入了相关的讨论群,经常在群里看到有人问项目怎么启动不起来,在此提供一下解决思路1.查看自己下载的项目目录通过文件夹结构,你能够看出来你下载的是一个maven项 ...

  7. nodejs入门 SSH服务器远程部署nodejs2

    服务器安装nodejs昨天好像出了点问题 今天参考的链接是http://nodejs.cn/download/package-manager/#debian-and-ubuntu-based-linu ...

  8. Cosh.1

    不管  先查壳 是VC++的 拿到OD  看看    经过跟踪 发现一个挺神奇的地方 再随便单步单步看看,发现CreateFileA返回的值总是-1 0040137A      83F8 00     ...

  9. Launcher 壁纸

    0.添加壁纸: 在给系统换默认的壁纸的时候,需要修改一些地方: 首先是默认的壁纸,这个是在framework中配置的,所以要修改framework中找到drawable-nodpi(这个文件夹中的内容 ...

  10. vs2010设置断点进行调试时不起作用

    1.打开vs2010 2.点击web下的“属性” 3.点击“生成” 4.点击最下方的“高级” 5.在“输出”-调试信息中选择“full”,点击确定按钮即可