学习pyopengl的时候,经常要不停的调试参数,以便理解和掌握绘图函数、变换函数的特点。但是一个程序一个程序的调整,很影响学习效率,于是想到用多线程或者多进程试验同时加载两个窗口,同时解决多个学习内容。
下面是试验的代码:
# pygame加PyOpenGL多进程编程,可以打开多个窗口,同时调用多个绘图函数,有利于学习测试时提高效率
# 可以在不同的窗口初始化函数、绘图函数中测试不同的参数和不同的图形绘制
# 调整、修改后一并运行
from multiprocessing import Process
import pygame as pg
from pygame.locals import *
import sys
from OpenGL.GL import *
from OpenGL.GLU import *
import numpy as np
import math
#————————————————————————————————————————————————————
# 谢尔平斯基三角锥部分
pTt=np.zeros(12).reshape(4,3)
dd=(60/180)*math.pi
ddsin=math.sin(dd)
def base_Tetra(l=1):
pTt[1]=1,0,0
pTt[2]=0.5*l,0,l*ddsin
pTt[3]=0.5*l,l*math.sqrt(2/3),l*(1/(2*math.sqrt(3)))
#绘制最基础的三角锥
def draw_Tetra(a,b,c,d):
glBegin(GL_LINE_LOOP)
glVertex3fv(a)
glVertex3fv(b)
glVertex3fv(c)
glEnd()
glBegin(GL_LINE_LOOP)
glVertex3fv(a)
glVertex3fv(b)
glVertex3fv(d)
glEnd()
glBegin(GL_LINE_LOOP)
glVertex3fv(b)
glVertex3fv(c)
glVertex3fv(d)
glEnd()
glBegin(GL_LINE_LOOP)
glVertex3fv(c)
glVertex3fv(a)
glVertex3fv(d)
glEnd()
#递归计算谢尔平斯基三角锥
def drawSherpin(a,b,c,d,n):
# 非常好理解的n次递归过程,比嵌套循环n次还要浅显易懂
if n<=1:
n=1
draw_Tetra(a*50,b*50,c*50,d*50)
else:
ab=(a+b)/2
bc=(b+c)/2
ac=(a+c)/2
ad=(a+d)/2
bd=(b+d)/2
cd=(c+d)/2
n=n-1
drawSherpin(a,ab,ac,ad,n)
drawSherpin(ab,b,bc,bd,n)
drawSherpin(ac,bc,c,cd,n)
drawSherpin(ad,bd,cd,d,n)
#————————————————————————————————————————————————————————
#圆锥部分
def drawscene():
#颜色标记
iPivot=1
#***可以调整下面的参数看看图形绘制的差别*******
#清除看不见的面(如显卡支持OpenGL会通过显卡实现,否则其通过软件实现)
#如果学习图形学可能需要自己用软件实现,挺艰辛的嘿嘿
#glEnable(GL_CULL_FACE)
#深度测试
glEnable(GL_DEPTH_TEST)
#图形背面设定,如果前面不设置CULL,默认画出背面,这里设为用线条画出背面
glPolygonMode(GL_BACK,GL_LINE)
# 保证窗口变化大小时,场景的角度变换不会受影响而错乱。
# 用glPushMatrix()会重置场景矩阵,则需要变量以实现动画
glMatrixMode(GL_MODELVIEW)
#glPushMatrix()
#-------
#旋转
glRotatef(1,1.,0.,0.)
glRotatef(1,0.,1.,0.)
glRotatef(1,0.,0.,1.)
#-------
#*******
#圆锥面,16个面
glBegin(GL_TRIANGLE_FAN)
glVertex3f(0.,0.,50.)
ang=0
for i in range(17):
x=25*np.cos(ang)
y=25*np.sin(ang)
if iPivot % 2 == 0:
glColor3f(0.,1.,0.)
else:
glColor3f(1.,0.,0.)
glVertex3f(x,y,0)
ang+=np.pi/8
iPivot+=1
glEnd()
#圆锥底面
glBegin(GL_TRIANGLE_FAN)
glVertex3f(0.,0.,0.)
#逆时针从2*np.pi开始-
#ang=2*np.pi
#顺时针从0角度开始+
ang=0
for i in range(17):
x=25*np.cos(ang)
y=25*np.sin(ang)
if iPivot % 2 == 0:
glColor3f(0.,1.,0.)
else:
glColor3f(1.,0.,0.)
glVertex3f(x,y,0)
#逆时针递减
#ang-=np.pi/8
#顺时针递增
ang+=np.pi/8
iPivot+=1
glEnd()
#由于没有使用变量进行动画绘制因此不需要下面语句
#glPopMatrix()
#glFlush()
#——————————————————————————————————————
# 窗口初始化与窗口缩放所需的部分
def setupRC():
#可以调整下面参数试试不同的效果
#顺时针正面否则默认逆时针正面
#GL_CW顺时针正面,GL_CCW逆时针正面(缺省是CCW)
#glFrontFace(GL_CW)
#着色方式是平涂,缺省是渐变色或者说柔化GL_SMOOTH
glShadeModel(GL_FLAT)
#初始化背景颜色为黑
glClearColor(0.,0.,0.,1.)
glTranslatef(0,0,-155)
# glRotatef(-45,1.,0.,0.)
def initScense(width,height):
pg.init()
display=(width,height)
aspectratio=display[0]/display[1]
pg.display.set_mode(display,DOUBLEBUF|OPENGL|RESIZABLE)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45,(display[0]/display[1]),10,500)
setupRC()
def changeSize(w,h):
# 在pygame环境里似乎不用超心h=0的危险,但是为了考虑图形正常绘制,可以考虑限制w和h的极小值
# 具体语句可自行添加
display=(w,h)
aspectratio=display[0]/display[1]
pg.display.set_mode(display,DOUBLEBUF|OPENGL|RESIZABLE)
glMatrixMode(GL_PROJECTION) #该行语句保证窗口大小变化后比例维持初始状态
glLoadIdentity()
gluPerspective(45,(display[0]/display[1]),10,500)
setupRC()
#————————————————————————————————————————————————————
# 事件处理部分,可以自行添加鼠标、键盘、游戏手柄和飞行模拟操纵杆事件
def handleEvent():
for event in pg.event.get():
if event.type==pg.QUIT:
pg.quit()
quit()
elif event.type==pg.VIDEORESIZE:
changeSize(event.w,event.h)
#——————————————————————————————————
# 绘图主循环部分
def mainloop(window_title):
while True:
handleEvent()
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
# 根据窗口编号选择不同的绘图函数
# 也可以考虑放在循环外提高效率,但是代码要重复写
# 如果不同的进程需要不同的OpenG初始化参数,这个选择可以放在更上一层
if window_title=='Window 1':
drawscene()
else:
#试试不加这个语句,然后缩放窗口什么后果
glMatrixMode(GL_MODELVIEW)
#旋转
glRotatef(1,1.,0.,0.)
glRotatef(1,0.,1.,0.)
glRotatef(1,0.,0.,1.)
drawSherpin(pTt[0],pTt[1],pTt[2],pTt[3],5)
pg.display.flip()
pg.time.wait(20)
#————————————————————————————————
# 进程部分,可以一个进程一个函数,不同进程的窗口初始化可以不一样,自己琢磨,这里我偷懒了
def window_process(window_title, width, height):
initScense(width,height)
mainloop(window_title)
# 初始化谢尔平斯基三角锥数组
base_Tetra()
# 创建两个窗口的进程
process1 = Process(target=window_process, args=("Window 1", 400, 300))
process2 = Process(target=window_process, args=("Window 2", 600, 400))
# 启动进程
process1.start()
process2.start()
# 等待进程结束(可选)
process1.join()
process2.join()
程序很简单,用两个进程分别打开OpenGL窗口,一个绘制谢尔平斯基三角锥,一个绘制圆锥,并且实现了窗口缩放同时保持比例和变换的持续性。