三维动画软件编辑界面可以在多视图和单视图之间随意切换,方便设计用户观察和编辑三维物体或者动画。掌握了OpenGL初步知识后很容易实现此功能。下面就是我在deepseek帮助下写的一段程序,实现了用数字键切换1、2、3、4视图,也可以用空格键切换四视图和其它视图,视图中绘制了一个立方体线框,前面绿色后面红色,使用者还可以通过按下鼠标左键拖动鼠标实现立方体滚动,并通过观察立方体线框色彩变换,感知投影是否正确。
#基于pygame设计一个类似glut的流程initScense()、changeSize()、handleEvent()、mainloop()……
#在windows和英特尔集显平台上完美显示四个视图,在华为uos显示四个视图,但是三个正投影显示不正常可能还要调试
import pygame as pg
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
import numpy as np
nRange=5 #x的范围绝对值,y按照屏幕比例调整
vLayout=4
oLayout=1
#view=[]
translation=[0,0,0]
rotation=[0,0,0]
w,h=1024,768
def draw_cube():
vertices = [
[[1, 1, -1],[1,0,0]],
[[1, -1, -1],[1,0,0]],
[[-1, -1, -1],[1,0,0]],
[[-1, 1, -1],[1,0,0]],
[[1, 1, 1],[0,1,0]],
[[1, -1, 1],[0,1,0]],
[[-1, -1, 1],[0,1,0]],
[[-1, 1, 1],[0,1,0]]
]# 立方体的含有颜色的点的数据,位置+颜色
edges = [
(0, 1), (1, 2), (2, 3), (3, 0),
(4, 5), (5, 6), (6, 7), (7, 4),
(0, 4), (1, 5), (2, 6), (3, 7)
]
glBegin(GL_LINES)
for edge in edges:
for vertex in edge:
glColor3fv(vertices[vertex][1])
glVertex3fv(vertices[vertex][0])
glEnd()
def set_ortho(w, h,viewType):
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
#glMatrixMode(GL_MODELVIEW)
if w<h:
glOrtho(-nRange,nRange,-nRange*h/w,nRange*h/w,0.1,100)
else:
glOrtho(-nRange*w/h,nRange*w/h,-nRange,nRange,0.1,100)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
if viewType == 'top':
gluLookAt(0, 10, 0, 0, 0, 0, 0, 0, -1)
elif viewType == 'front':
gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0)
elif viewType == 'left':
gluLookAt(-10, 0, 0, 0, 0, 0, 0, 1, 0)
elif viewType == 'right':
gluLookAt(10, 0, 0, 0, 0, 0, 0, 1, 0)
def set_perspective(width, height):
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45, (width/height), 0.1, 45)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt(5, 5, 5, 0, 0, 0, 0, 1, 0)
def draw_grid(type):
grid_size=10
grid_step=1
if type == 'top' or 'pespect':
glBegin(GL_LINES)
for i in range(-grid_size, grid_size+1, grid_step):
glColor3f(0.5, 0.5, 0.5)
glVertex3f(i, 0, -grid_size)
glVertex3f(i, 0, grid_size)
glVertex3f(-grid_size, 0, i)
glVertex3f(grid_size, 0, i)
glEnd()
if type == 'left':
glBegin(GL_LINES)
for i in range(-grid_size, grid_size+1, grid_step):
glColor3f(0.5, 0.5, 0.5)
glVertex3f(0, i, -grid_size)
glVertex3f(0, i, grid_size)
glVertex3f(0,-grid_size, i)
glVertex3f(0, grid_size, i)
glEnd()
if type == 'right':
glBegin(GL_LINES)
for i in range(-grid_size, grid_size+1, grid_step):
glColor3f(0.5, 0.5, 0.5)
glVertex3f(0, i, -grid_size)
glVertex3f(0, i, grid_size)
glVertex3f(0,-grid_size, i)
glVertex3f(0, grid_size, i)
glEnd()
def renderViewport(x,y,w,h,view_type):
glViewport(x, y, w, h)
glScissor(x, y, w, h)
glEnable(GL_SCISSOR_TEST)
glClear(GL_DEPTH_BUFFER_BIT)
if view_type == 'perspective':
set_perspective(w,h)
else:
set_ortho(w,h,view_type)
draw_grid(view_type)
glPushMatrix()
glTranslatef(*translation)
glRotatef(rotation[0], 1, 0, 0)
glRotatef(rotation[1], 0, 1, 0)
# draw_grid(view_type)
draw_cube()
glPopMatrix()
glDisable(GL_SCISSOR_TEST)
def showLayout(w,h):
global vLayout
print(vLayout,w,h)
if vLayout==1:
renderViewport(0, 0, w, h, 'perspective')
if vLayout == 4:
# 四视图布局
w, h = w//2, h//2
renderViewport(0, h, w, h, 'top')
renderViewport(w, h, w, h, 'front')
renderViewport(0, 0, w, h, 'left')
renderViewport(w, 0, w, h, 'perspective')
if vLayout == 2:
if w >= h:
w = w//2
renderViewport(0, 0, w, h, 'perspective')
renderViewport(w, 0, w, h, 'front')
else:
h=h//2
renderViewport(0, h, w, h, 'perspective')
renderViewport(0, 0, w, h, 'front')
if vLayout == 3:
if w >= h:
if w >= 1.5*h:
renderViewport(0, 0, h, h, 'perspective')
renderViewport(h, 0, w-h, h//2, 'front')
renderViewport(h, h, w-h, h//2, 'top')
else:
renderViewport(0, 0, h//2, h, 'perspective')
renderViewport(h//2, 0, w-h//2, h//2, 'front')
renderViewport(h//2, h//2, w-h//2, h//2, 'top')
if w < h:
if h >= 1.5*w:
renderViewport(0, h//2, w, h//2, 'perspective')
renderViewport(0, 0, h-w, h//2, 'front')
renderViewport(w//2, 0, h-w, w//2, 'top')
else:
renderViewport(0, 0, w, w//2, 'perspective')
renderViewport(h//2, 0, w//2, w-h//2, 'front')
renderViewport(0, w//2, w//2, w-h//2, 'top')
def initScense():
global nRange,w,h,screen
pg.init()
display=(w,h)
aspectratio=display[0]/display[1]
screen=pg.display.set_mode(display,DOUBLEBUF|OPENGL|RESIZABLE)
pg.display.set_caption('多视图切换')
nRange=5
# 初始化OpenGL参数
glEnable(GL_DEPTH_TEST)
# glEnable(GL_LIGHTING)
# glEnable(GL_LIGHT0)
glEnable(GL_COLOR_MATERIAL)
glClearColor(0.2, 0.2, 0.2, 1.0)
def changeSize(w,h):
global nRange
display=(w,h)
aspectratio=display[0]/display[1]
pg.display.set_mode(display,DOUBLEBUF|OPENGL|RESIZABLE)
def handleEvent():
global oLayout,vLayout,w,h
for event in pg.event.get():
if event.type==pg.QUIT:
pg.quit()
quit()
elif event.type==pg.VIDEORESIZE:
w,h=event.size
changeSize(event.w,event.h)
elif event.type == pg.MOUSEMOTION:
if event.buttons[0]:
dx,dy=event.rel
rotation[0]+=dy*0.5
rotation[1]+=dx*0.5
elif event.type == pg.KEYDOWN:
if event.key == K_SPACE:
if vLayout != 4:
oLayout=vLayout
vLayout=4
else:
vLayout=oLayout
elif event.key == K_1:
vLayout=1
oLayout=1
elif event.key == K_2:
vLayout=2
oLayout=2
elif event.key == K_3:
vLayout=3
oLayout=3
elif event.key == K_4:
if vLayout != 4:
oLayout=vLayout
vLayout=4
def mainloop():
global w,h
while True:
handleEvent()
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
showLayout(w,h)
pg.display.flip()
pg.time.wait(20)
#main
initScense()
mainloop()
在此基础上可以添加选择、拖曳、修改、保存等功能,完成一个简单的三维物体制作软件。如果添加高精度渲染和动画功能,就能做一个比较完善的三维动画软件,有兴趣的朋友可以试一试。