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()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM