当前位置:网站首页>七夕,当爱神丘比特遇上牛郎和织女
七夕,当爱神丘比特遇上牛郎和织女
2022-08-04 21:33:00 【天元浪子】
七夕是中国民间的传统节日,不同时代、不同地域的人们给这个节日赋予了不同的含义。在漫长的演变过程中,七夕成了牛郎织女相会的日子。正因为这个美丽的爱情传说,七夕被视为中国最具浪漫色彩的、象征爱情的节日。在西风东渐的背景下,七夕又成了中国的“情人节”。
既然是情人节,浪漫的程序员总喜欢搞点花样出来,为紧张且平淡的生活添点色彩。今天给各位带来的是3D动画版的丘比特爱情之剑:一只金色的丘比特爱情之剑以慢镜头方式缓缓刺中一个脉动的红心,红心的主人将会无法控制地爱上TA所看到第一个人。我猜,当初牛郎和织女一定是被丘比特的爱情之剑射中以后才相爱的,毕竟,他们都生活在天上——西方文化中,木星(Jupiter)就是小爱神丘比特,金星(Venus)则是大爱神维纳斯。
在丘比特的爱情之剑出场前,先用matplotlib绘制一颗2D的红心热热身。
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-np.pi/2, np.pi/2, 1000)
y1 = np.power(np.cos(x),0.5) * np.cos(200*x) + np.power(np.absolute(x),0.5) - 0.7
y2 = np.power(4-np.power(x, 2), 0.01)
plt.plot(x, y1*y2, c='r')
plt.show()

放大一点看的话,就会发现上面这颗红心其实是一条连续上下波动的曲线。下面的红心,是一个真正封闭的心形,只不过是由四条曲线首尾相连组成的。
import numpy as np
import matplotlib.pyplot as plt
x1 = np.linspace(0, 2, 300)
x2 = np.linspace(0, -2, 300)
y11 = (np.power(x1, 2/3) + np.power(np.power(x1, 4/3)-4*np.power(x1, 2)+4, 0.5))/2 - 0.12
y12 = (np.power(x1, 2/3) - np.power(np.power(x1, 4/3)-4*np.power(x1, 2)+4, 0.5))/2
y21 = (np.power(-x2, 2/3) + np.power(np.power(-x2, 4/3)-4*np.power(-x2, 2)+4, 0.5))/2 - 0.12
y22 = (np.power(-x2, 2/3) - np.power(np.power(-x2, 4/3)-4*np.power(-x2, 2)+4, 0.5))/2
plt.plot(x1, y11, c='r')
plt.plot(x1, y12, c='r')
plt.plot(x2, y21, c='r')
plt.plot(x2, y22, c='r')
plt.show()

那么,可以用一笔画一个心形吗?当然可以,极坐标方程 r = arccos(sinθ)就是一条心形线,只是形状不够完美而已。
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(0, 2*np.pi, 1000)
x = np.arccos(np.sin(theta)) * np.cos(theta)
y = np.arccos(np.sin(theta)) * np.sin(theta)
plt.plot(x, y, c='r')
plt.show()

是时候展示3D版的红心了。运行下面的代码,除了需要numpy模块,还需要安装wxgl模块——基于PyOpenGL的三维数据绘图工具包。
pip install wxgl
关于wxgl模块的更多详情,请点击十分钟玩转3D绘图:WxGL完全手册,这里是中文文档。
下面是3D版的红心的绘制代码,
import numpy as np
import wxgl.glplot as glt
a = np.linspace(0, 2*np.pi, 500)
b = np.linspace(0.5*np.pi, -0.5*np.pi, 500)
lons, lats = np.meshgrid(a, b)
w = np.sqrt(np.abs(a - np.pi)) * 2
x = 2 * np.cos(lats) * np.sin(lons) * w
y = -2 * np.cos(lats) * np.cos(lons) * w
z = 2 * np.sin(lats)
glt.mesh(x, y, z, color='crimson') # crimson - 绯红
glt.show()
是不是很简单?wxgl的使用风格几乎和matplotlib完全一致。拖动鼠标,就可以看到这个3D版的红心的前后左右了。

接下来,这段代码将红心数据的生成封装了一个函数,然后调用自定义的模型变换函数,这颗红心就跳动起来了。
import numpy as np
import wxgl.glplot as glt
def red_heart(r, slices=100, thick=2.0, shift=(0,0,0)):
"""返回红心顶点数据"""
a = np.linspace(0, 2*np.pi, slices)
b = np.linspace(0.5*np.pi, -0.5*np.pi, slices)
lons, lats = np.meshgrid(a, b)
w = np.sqrt(np.abs(a - np.pi)) * thick
x = r * np.cos(lats) * np.sin(lons) * w + shift[0]
y = -r * np.cos(lats) * np.cos(lons) * w + shift[1]
z = r * np.sin(lats) + shift[2]
return x, y, z
def heart_beat(t):
"""心跳函数"""
t %= 1000
if t < 300:
scale = 1 + t/3000
elif t > 700:
scale = 1 + (1000-t)/3000
else:
scale = 1.1
return (scale,)
glt.mesh(*red_heart(2), color='crimson', transform=heart_beat)
glt.show()
点击左侧工具条上的播放按钮,这颗红心就会按照60次/秒的心率跳动起来。熟悉了wxgl的使用,不难读懂下面这个完整的丘比特爱情之箭的代码。
import numpy as np
import wxgl
import wxgl.glplot as glt
def red_heart(r, slices=100, thick=2.0, shift=(0,0,0)):
"""返回红心顶点数据"""
a = np.linspace(0, 2*np.pi, slices)
b = np.linspace(0.5*np.pi, -0.5*np.pi, slices)
lons, lats = np.meshgrid(a, b)
w = np.sqrt(np.abs(a - np.pi)) * thick
x = r * np.cos(lats) * np.sin(lons) * w + shift[0]
y = -r * np.cos(lats) * np.cos(lons) * w + shift[1]
z = r * np.sin(lats) + shift[2]
return x, y, z
def heart_beat(t):
"""心跳函数"""
t %= 1000
if t < 300:
scale = 1 + t/3000
elif t > 700:
scale = 1 + (1000-t)/3000
else:
scale = 1.1
return (scale,)
def arrow_fly(t):
"""丘比特之箭飞行函数"""
t %= 4000
if t > 2000:
return ((0,-2,40-t/100),)
else:
return ((0,-2,0),)
def heart_fly(t):
"""丘比特之箭飞行函数"""
t %= 4000
if t > 2000:
return ((0,0,1,90), (0,-2,40-t/100))
else:
return ((0,0,1,90), (0,-2,0))
glt.figure(azim=50, elev=16, style='gray') # 设置初始方位角、高度角、背景色
glt.mesh(*red_heart(2), color='crimson', transform=heart_beat) # 绘制跳动的红心
x, y, z = red_heart(0.2, thick=3.0, shift=(0,-8,0)) # 生成心形箭头顶点数据
glt.mesh(x, -z, y, color='crimson', transform=heart_fly) # 绘制心形箭头
light = wxgl.SunLight(roughness=0, metalness=0, shininess=0.5) # 箭杆灯光
glt.cylinder((0,0,-8), (0,0,9), 0.1, color='goldenrod', transform=arrow_fly, light=light) # 绘制箭杆
vs = [(-1,1,11), (1,-1,11), (1,-1,6), (-1,1,6),(-1,-1,11), (1,1,11), (1,1,6), (-1,-1,6)] # 箭尾顶点数据
texture = wxgl.Texture(r'res\feather.png') # 箭尾羽毛纹理
texcoord = [(0,1), (0,0), (1,0), (1,1),(0,1), (0,0), (1,0), (1,1)] # 箭尾纹理坐标
light = wxgl.BaseLight() # 箭尾灯光
glt.quad(vs, texture=texture, texcoord=texcoord, transform=arrow_fly, light=light) # 绘制箭尾
glt.show()
wxgl的工具条提供了录制gif和MP4文件的功能,下面的gif就是使用wxgl自带的录制功能生成的。

代码中用到了羽毛的纹理,请下载这个图片,并保存到代码指定的位置。
边栏推荐
- Develop your own text recognition application with Tesseract
- dotnet 启动 JIT 多核心编译提升启动性能
- dotnet 通过 WMI 获取系统安装软件
- 3. Byte stream and character stream of IO stream
- 知识分享|如何设计有效的帮助中心,不妨来看看以下几点
- LayaBox---TypeScript---Problems encountered at first contact
- 热力学相关的两个定律
- Configure laravel queue method using fort app manager
- 信创是什么意思?涉及哪些行业?为什么要发展信创?
- 【uiautomation】微信好友列表获取(存储到txt中)
猜你喜欢
随机推荐
Android 面试——如何写一个又好又快的日志库?
PRIMAL: Pathfinding via Reinforcement and Imitation Multi-Agent Learning Code Analysis
matlab drawing
国际项目管理师PMP证书,值得考嘛?
Dotnet using WMI software acquisition system installation
《剑指offer》刷题分类
经验分享|盘点企业进行知识管理时的困惑类型
bracket matching
【PCBA program design】Grip dynamometer program
Driving point cloud format changes bring efficiency improvement
buu web
Moke, dynamic image resource package display
PCBA方案设计——厨房语音秤芯片方案
如何将二叉搜索树转化为一个有序的双向链表(原树上修改)
数电快速入门(三)(卡诺图化简法的介绍)
PowerCLi import license to vCenter 7
AI/ML无线通信
LeetCode: 406. 根据身高重建队列
搬走地下空间开发利用“绊脚石” 中地数码取得地下空间透明化技术突破
JWT主动校验Token是否过期









