zoukankan      html  css  js  c++  java
  • Python>>>创建一个简单的3D场景(1)

    首先安装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()
  • 相关阅读:
    WF 学习笔记 (1) 浅谈 WF 和 MVC 架构
    从HelloWorld看iphone程序的生命周期
    android开发我的新浪微博客户端阅读微博UI篇(6.1)
    关于微博服务端API的OAuth认证实现
    iphone开发我的新浪微博客户端开篇
    一个完整的新浪微博客户端android版OAuth认证示例
    android开发我的新浪微博客户端OAuth认证过程中用WebView代替原来的系统自带浏览器
    iphone开发我的新浪微博客户端用户登录准备篇(1.1)
    android开发我的新浪微博客户端登录页面功能篇(4.2)
    android开发我的新浪微博客户端登录页面UI篇(4.1)
  • 原文地址:https://www.cnblogs.com/legion/p/6225920.html
Copyright © 2011-2022 走看看