Python作为目前较广泛的编程语言, 用于制作3D游戏可谓得心应手。本文讲解使用Python pyglet库自制简易3D引擎的方法技巧。

上篇:Python pyglet 自制3D引擎入门(一) – 绘制几何体、创建3D场景

目录

  • 导入pyglet及初始化
  • 相机控制
  • 3D图形绘制
  • 用计时器实现动画效果
  • 主程序实现

先放效果图:

导入pyglet及初始化

pyglet.window部分用于实现窗口操作, pyglet.gl以及pyglet.gl.glu模块包含了OpenGL的绘图函数, 也是3D引擎中的关键部分。
pyglet模块可通过pip安装: pip install pyglet

import pyglet
from pyglet.gl import *
from pyglet.gl.glu import *
from pyglet.window import key
import math
from random import random, randint

定义常量和数据:

WIDTH=400;HEIGHT=400
angle_xy = math.pi / 2 # X-Y平面内的相机角度, 弧度制(0-360°变为0-2π)
angle_z = 0 # 相机绕Z轴旋转的角度
distance = 20
centerx,centery,centerz = 38,9, -11 # 中心点位置, 相机绕中心点旋转
data = [(3.2045, 50.7902), (1.5227, 49.5507), (0.2268, 47.9115), (-0.6292, 46.0584), (-0.9964, 44.1779), (-0.8378, 42.4295), (-0.5548, 41.6411), (-0.1348, 40.9221),(0.4219, 40.2782), (1.9425, 39.2276), (2.9045, 38.8233), (4.0, 38.5), (2.9045, 38.1766), (1.9424, 37.7722), (0.4218, 36.7216), (-0.1349, 36.0778), (-0.5548, 35.3589), (-0.8378, 34.5706), (-0.9964, 32.8226),(-0.6291, 30.9425), (0.227, 29.09), (1.5229, 27.4513), (3.2048, 26.2122), (5.2203, 25.5298), (7.5231, 25.5104), (10.0749, 26.2121), (12.8454, 27.6578), (15.812, 29.848),(18.9593, 32.7712), (22.2779, 36.4131), (24.0, 38.5), (22.2778, 40.5874), (18.9591, 44.2302), (15.8118, 47.1541), (12.8451, 49.3448), (10.0746, 50.7907),(7.5228, 51.4924), (5.22, 51.4729)]# 心形的矢量图数据
z1=8; z2=10 # 心形两个面的z坐标

初始化pygletWindow对象, 用于绘制图形、接收事件。

window = pyglet.window.Window(height=HEIGHT, width=WIDTH)

相机控制

类似于一些3D游戏,我们这里的相机需要实现360°无死角的旋转。

convert_pos()用于转换相机的坐标。其中:
相机绕着一个中心点, 2个方向旋转。
想象相机和中心点距离不变, 中心点是球心, 相机就相当于在一个球体表面自由移动。程序中angle_xy类似于球体的“经度”, angle_z类似“纬度”。通过“经度”和“纬度”, 就能控制相机移动。
另外, 一些3D游戏除了使用以上的“经度”和“纬度”, 还使用了第三根轴控制相机的旋转。
像下面这样:

def convert_pos():# 将相机角度转换为相机的X,Y,Z坐标if math.pi/2 < angle_z < math.pi * 1.5:flag = -1 # 相机朝下else:flag = 1 # 相机朝上cam_x=math.cos(angle_xy)*distance *math.cos(angle_z) + centerxcam_y=math.sin(angle_xy)*distance *math.cos(angle_z) + centerycam_z=math.sin(angle_z)*distance + centerzreturn cam_x,cam_y,cam_z,flag

这是绑定pyglet窗口的事件
按↑,↓,←,→键或拖动鼠标切换查看角度,按Page Up / Page Down键或滚动鼠标,调整远近。

@window.event
def on_key_press(k,_):global angle_xy,angle_z,distanceif k==key.DOWN: # 下angle_z -= math.pi * 1/18 # 10°elif k==key.UP:# 上angle_z += math.pi * 1/18elif k==key.LEFT: # 左angle_xy -= math.pi * 1/18elif k==key.RIGHT: # 右angle_xy += math.pi * 1/18elif k==key.PAGEUP: # page updistance/=1.15elif k==key.PAGEDOWN: # page downdistance*=1.15angle_z %= math.pi*2on_draw()@window.event
def on_mouse_drag(x,y,dx,dy,btn,_): # 拖动鼠标, dx和dy为鼠标位置变化的多少global angle_xy, angle_zangle_xy -= dx / 100angle_z -= dy / 100angle_z %= math.pi * 2on_draw()@window.event
def on_mouse_scroll(x,y, _, d): # 滚动鼠标, d为滚动的多少global distancedistance /= 1.1**don_draw()

3D图形绘制

这是window对象的on_draw事件,调用openGL绘图的代码都应该放在这个函数里面。
如果代码看不懂,可以看上篇中关于openGL 3D绘图的介绍。

@window.event  # 表示绑定 window 对象的事件
def on_draw(): # 注意函数名, 必须是on_draw才能绑定绘制的事件glMatrixMode(GL_PROJECTION)  # 设置当前矩阵为投影矩阵glLoadIdentity()# 透视投影, 前4个参数类似游戏中的FOV(视角大小), # 后2个参数分别是物体与相机的最近、最远距离glFrustum(-5, 5, -5, 5, 2, 1000)  # 透视投影glMatrixMode(GL_MODELVIEW)  # 模型视图矩阵glLoadIdentity()glViewport(0, 0, WIDTH, HEIGHT)window.clear() # 或 glClear(GL_COLOR_BUFFER_BIT)glClear(GL_DEPTH_BUFFER_BIT) # 清除深度(z排序)缓冲区# 改变相机位置和角度cam_x,cam_y,cam_z,flag = convert_pos()gluLookAt(cam_x,cam_y,cam_z,centerx,centery,centerz,0,0,flag) # 0,0,flag为相机朝上方向for dx,dy,dz in lst_pos: # 绘制列表中的各个心形draw_heart(dx,dy,dz)glFlush() # 刷新绘图缓冲区

下面的draw_heart()函数用于在不同位置绘制3D心形, 根据二维的心形矢量图数据, 绘制正面和侧面, 形成三维的形状。glVertex3f函数定义心形每个顶点的坐标。

def draw_heart(dx,dy,dz): # 绘制心形# dx, dy, dz为心形从中心点向X, Y, Z轴正方向平移多少# 绘制顶、底面glBegin(GL_POLYGON)glColor3f(random()*0.5+0.5, 0, random()*0.5+0.5) # 随机生成颜色for x, y in data:glVertex3f(y+dx, z1+dy, -x+dz) # 使用y,z和-x, 旋转心形, 使心形更易于查看glEnd()glBegin(GL_POLYGON)for x, y in data:glVertex3f(y+dx, z2+dy, -x+dz)glEnd()# 绘制侧面glColor3f(0.5, 0, 0.5)for i in range(len(data)):if i + 1 == len(data):  # 到达列表末尾next_point = data[0]else:next_point = data[i + 1]point = data[i]glBegin(GL_POLYGON)glVertex3f(point[1]+dx, z1+dy, -point[0]+dz)glVertex3f(next_point[1]+dx, z1+dy, -next_point[0]+dz)glVertex3f(next_point[1]+dx, z2+dy, -next_point[0]+dz)glVertex3f(point[1]+dx, z2+dy, -point[0]+dz)glEnd()

用计时器实现动画效果

pyglet库自带了计时器功能。首先,导入pyglet.clock模块 (有点像pygame)。

from pyglet import clock

通过clock模块中的schedule_interval函数,可以设定计时器间隔。这里程序每隔0.02秒,调用一次animate函数。在animate函数中再加入实现动画的代码。

def animate(event):global centerxcenterx+=1xpos=lst_pos[0][0]lst_pos[0]=(xpos+1,0,0)on_draw() # 重新绘制# 每隔0.02秒,调用一次animate函数
clock.schedule_interval(animate, 0.02)

主程序实现

主程序随机生成多个心形, 类似游戏中使用的过程生成技术。

# 随机生成多个心形
lst_pos = [(0,0,0)] # 中心的心形
for i in range(20):lst_pos.append((randint(-200,200),randint(-200,200),randint(-200,200)))
glClearColor(0.8, 1, 1, 1)
glEnable(GL_DEPTH_TEST) # 开启深度(z排序), 使程序支持近的物体遮挡远的物体
pyglet.app.run()

学习了这么多, 应该可以编写自己的简易3D游戏了吧! 欢迎点赞、收藏。

作者的其他3D程序作品, 见作者的gitcode:gitcode.net/qfcy_/python/-/tree/master/opengl。
下面是自己的星空程序(space.py)的截图:

Python pyglet 自制3D引擎入门(二) -- 绘制立体心形,动画和相机控制相关推荐

  1. Python pyglet 自制3D引擎入门(一) -- 绘制几何体、创建3D场景

    Python作为目前较广泛的编程语言, 用于制作3D游戏可谓得心应手.本文讲解应用Python pyglet库绘制3D场景的入门知识. 下篇:Python pyglet 自制3D引擎入门(二) – 绘 ...

  2. python绘制立体心形折纸图解_简单带翅膀的爱心立体卡片制作方法

    简单的爱心立体卡片手工制作,随时随地都可以用上,把你的心意都放进去.想要给你心目中的那个他(她)一份不一样的礼物吗?浪漫的情人节,还有什么能比自制的爱心立体卡片更能表达你对他(她)满满爱意呢?不要再去 ...

  3. python绘制立体心形_python画出心形图

    使用SeasLog打造PHP项目中的高性能日志组件(一) 云智慧(北京)科技有限公司 高驰涛 什么是SeasLog SeasLog是一个C语言编写的PHP扩展,提供一组规范标准的功能函数,在PHP项目 ...

  4. python绘制立体心形折纸图解_PS制作超漂亮的立体的心形折纸效果

    今天为大家分享PS制作超漂亮的立体的心形折纸效果方法,教程难度不是很大,制作出来的折纸效果非常漂亮,好了,一起来学习吧! 背景选择灰色的渐变底 如下 新建一个图层,可以使用其他的图案 或者 图形 但是 ...

  5. python绘制立体心形折纸图解_立体幸运心、桃心简单折纸方法图解

    五颜六色的,小小的,你可以将你的心事写入其中,送给你最爱的人,如此浪漫你心爱的人一定会很开心的 立体桃心折纸方法需要准备的工具和材料:彩纸一张.巧手一双.细笔芯可有可无. 立体桃心折纸方法步骤图解: ...

  6. Godot3游戏引擎入门之四:给主角添加动画(上)

    一.前言 说明:我目前使用的 Godot 3.1 预览版,所以会与 Godot 3 的版本有一些区别,界面影响不大,如果要使用我上传的 Github Demo 代码,记得去官网下载 3.1 预览版(或 ...

  7. Html-照片的逐步出现 、心形动画制作、3d立方体魔方、鼠标划过box阴影练习

    Html-照片的逐步出现 .心形动画制作.3d立方体魔方.鼠标划过box阴影练习 一.照片的逐步出现 <!DOCTYPE html> <html lang="en" ...

  8. 【matlab】 动态绘制三维心形图

    [转载]matlab动态绘制三维心形图 matlab动态绘制三维心形图程序如下,核心是isosurface函数,verts存储了心形曲面各点的坐标,而faces存储了各点的连接顺序. clear fi ...

  9. python画立体心形折纸图解_各种心形折纸步骤图解

    各种心形折纸步骤图解 导读 :立体爱心的折法有很多这里再分享一个立体爱心的折法,这个立体爱心折纸图解教程非常的好学,看了就会做,能够让你轻松学会怎么折立体心形折纸. 下面是小编整理的各种心形折纸步骤图 ...

最新文章

  1. Android 数据库之Cursor
  2. ITK:仅将过滤器应用于图像的指定区域
  3. 7-2 jmu-Java-01入门-取数字 (2 分)
  4. python基础开发环境_Python基础教程,第一讲,开发环境搭建
  5. excel合并计算_【Excel】合并计算和模拟分析的应用
  6. webbrowser 访问iframe拒绝访问_Win10系统下Documents and Settings系统文件夹拒绝访问解决方法...
  7. AS3学习笔记(一)基础知识
  8. Linux系统中设置静态ip地址
  9. 《java入门第一季》之面向对象(static关键字内存图解)
  10. ARX二次开发 遍历删除所有的约束
  11. 成功解决raise KeyError(f“None of [{key}] are in the [{axis_name}]“)KeyError: “None of [Index([‘age.in.y
  12. java 富文本 过滤xss_富文本XSS过滤
  13. LeetCode.1046-最后的石头重量(Last Stone Weight)
  14. 大学计算机基础教程实验答案,大学计算机基础试验教程习题参考答案
  15. 2021年7月电动汽车保有量,充电站数量
  16. 【Codeforces】1635E Cars 题解
  17. 为什么微信连接不上服务器失败怎么回事啊,微信为什么一直提示连接失败请检查网络设置...
  18. 测绘资质在线处理资质问题
  19. 图片添加水印的方法,这个真的很实用!
  20. cocos Creator android 上传图片与数据

热门文章

  1. 维昇药业大中华区研发制造基地奠基;复星医药与英矽智能宣布达成战略合作 | 医药健闻...
  2. 商城-购物车-购物车功能分析
  3. 随身wifi和路由器有何不同?
  4. 继中国天眼之后,贵州再现“天眼”...
  5. Deformable detr源码分析
  6. 网站更换国外服务器,海外服务器更换要做好3件事
  7. BUUCTF misc 专题(87)[DDCTF2018](╯°□°)╯︵ ┻━┻
  8. 国内计算机三大顶级期刊+ JCST
  9. 离线数据清洗,Spark和Python Pandas对比
  10. VBA实例2 Word表格编号及金额统计