python绘图烟花,Python opengl

  python绘图烟花,Python opengl

  现在是春节,边肖今天为您带来一场由皮托诺彭绘制的烟火盛会。文中详细讲解了实施步骤,有兴趣的朋友可以跟着边肖去试试。

  00-1010 1.安装WxGL2。赶紧体验一下吧。3.编写自己的着色器。4.绽放的烟花忙了一年,今天终于放假了。本来打算好好休息一下,但是半天下来感觉有点无聊。看到家人朋友都在忙着过年,我就用OpenGL为即将到来的新年导演一场烟火盛会。

  说到OpenGL,很多人会觉得它很复杂,其实不然。只要掌握了几个基本概念,借助工具和软件,任何人都可以轻松使用。在制作fireworks之前,我想先介绍一下WxGL,这是一个快速可视化3D数据的工具。

  

目录

  WxGL是基于PyOpenGL的三维数据可视化库,以wx为显示后端,提供Matplotlib风格的交互应用模式。WxGL还可以与wxPython无缝结合,在wx的表单上绘制3D模型。使用pip命令快速安装WxGL和它所依赖的其他模块。

  pip安装wxgl

  

1. 安装WxGL

  下面几行代码绘制了一个纯色球体,其中心位于坐标原点,半径为1。如果忽略模块名,这些代码完全符合Matplotlib的风格。

  将wxgl.wxplot作为plt导入

  plt.uvsphere((0,0,0),1,color=cyan )

  Plt.title(快速体验:$ x ^ 2y ^ 2=1 $ )

  plt.show()

  生成地球模型是如此简单。

  plt.uvsphere((0,0,0),1,texture=res/earth.jpg ,xflip=True,yflip=False)

  plt.show()

  让地球旋转是小菜一碟。

  plt.uvsphere((0,0,0),1,

  texture=res/earth.jpg ,

  xflip=True,

  yflip=False,

  transform=lambda tn,gms,tms : ((0,1,0,(0.01*tms)60),)

  )

  plt.show()

  选中“屏幕录制”并单击“播放”按钮,将其保存为gif文件或mp4/avi格式的视频文件。

  这是代码中使用的地球纹理图片,可以直接下载使用。

  

2. 快速体验

  WxGL不仅提供了线段、散点、曲面、三维等值面等一系列绘图功能,还支持用户自定义着色器程序,实现更复杂的功能。以下示例使用粒子技术来模拟烟花起飞的过程。

  # -*-编码: utf-8 -*-

  将numpy作为np导入

  导入wxgl

  将wxgl.wxplot作为plt导入

  定义上升(n、位置、h、v、a、周期):

  烟花升空模型

  粒子数

  位置-初始位置

  h-上升笔划

  v-初始速度

  上升加速度

  循环周期

  vshader_src=

  #版本330核心

  在vec4 a_Position中;

  在vec4 a _ Color

  在浮点a_Delay中;//粒子发射延迟时间(秒)

  均匀浮动u _ Ts//持续时间

  均匀浮动u _ V;//初始速度

   uniform float u_A; // 上升加速度

   uniform mat4 u_MVPMatrix;

   out vec4 v_Color;

   out float v_Ts;

   void main() {

   float t = u_Ts - a_Delay;

   if (t < 0) t = 0;

   float s = u_V * t + 0.5 * u_A * t * t;

   gl_Position = u_MVPMatrix * vec4(a_Position.x, a_Position.y+s, a_Position.z, a_Position.w);

   gl_PointSize = 1;

   v_Color = a_Color;

   v_Ts = u_Ts;

   }

   """

   fshader_src = """

   #version 330 core

   in vec4 v_Color;

   uniform float u_Tmax;

   in float v_Ts;

   void main() {

   if(v_Ts > u_Tmax) discard;

   vec2 temp = gl_PointCoord - vec2(0.5);

   float f = dot(temp, temp);

   if(f > 0.25) discard;

   gl_FragColor = vec4(v_Color.rgb, 1);

   }

   """

   vs = np.array(pos) + (np.random.random((n,3)) - 0.5) * h/100

   color = np.tile(np.array((1.0,1.0,0.8)), (n,1))

   delay = np.float32(np.absolute(np.random.randn(n))) / 10

   tmax = (pow(v*v+2*a*h, 0.5)-v)/a + delay.max()

   m = wxgl.Model(wxgl.POINTS, vshader_src, fshader_src, sprite=True)

   m.set_vertex(a_Position, vs)

   m.set_color(a_Color, color)

   m.set_argument(a_Delay, delay)

   m.set_argument(u_Ts, lambda tn,gms,tms:(tms/1000)%cycle)

   m.set_argument(u_V, v)

   m.set_argument(u_A, a)

   m.set_argument(u_Tmax, tmax)

   m.set_mvp_matrix(u_MVPMatrix) # 设置模型矩阵、视点矩阵和投影矩阵

   return m

  vs = np.array([

   [-1.5,2,1], [-1.5,0,1], [1.5,2,1], [1.5,0,1],

   [-1.5,2,-1], [-1.5,0,-1], [1.5,2,-1], [1.5,0,-1]])

  vs = vs[[0,1,2,3,0,2,1,3,4,5,6,7,4,6,5,7,0,4,1,5,2,6,3,7]]

  m = rise(n=500, pos=(0,0,0), h=1.5, v=2, a=-1.2, cycle=5)

  plt.figure(zoom=0.7, elev=10)

  plt.line(vs, color=(0,1,1), method=isolate) # 六面体线框,表示烟花燃放的空间

  plt.model(m)

  plt.show()

  

  

  

4. 绽放的烟花

  只要理解了烟花升空的代码,很容易写出烟花在空中爆炸的着色器程序。下面的代码除了烟花升空的着色器,还提供了两种烟花爆炸的着色器,其中用到了一个纹理图片,可直接下载下面这张图使用。

  

  如果将上面的纹理图片替换成文字,就可以在烟花爆炸的瞬间显示出文字了。WxGL提供了一个文本转PIL图形对象的函数,可以直接作为纹理使用。

  

# -*- coding: utf-8 -*-

  import numpy as np

  import wxgl

  import wxgl.wxplot as plt

  def rise(n, pos, h, v, a, cycle):

   """烟花升空模型

   n - 粒子数量

   pos - 初始位置

   h - 上升行程

   v - 初始速度

   a - 上升加速度

   cycle - 循环周期

   """

   vshader_src = """

   #version 330 core

   in vec4 a_Position;

   in vec4 a_Color;

   in float a_Delay; // 粒子发射延迟时间(s)

   uniform float u_Ts; // 持续时间(s)

   uniform float u_V; // 初始速度

   uniform float u_A; // 上升加速度

   uniform mat4 u_MVPMatrix;

   out vec4 v_Color;

   out float v_Ts;

   void main() {

   float t = u_Ts - a_Delay;

   if (t < 0) t = 0;

   float s = u_V * t + 0.5 * u_A * t * t;

   gl_Position = u_MVPMatrix * vec4(a_Position.x, a_Position.y+s, a_Position.z, a_Position.w);

   gl_PointSize = 1;

   v_Color = a_Color;

   v_Ts = u_Ts;

   }

   """

   fshader_src = """

   #version 330 core

   in vec4 v_Color;

   uniform float u_Tmax;

   in float v_Ts;

   void main() {

   if(v_Ts > u_Tmax) discard;

   vec2 temp = gl_PointCoord - vec2(0.5);

   float f = dot(temp, temp);

   if(f > 0.25) discard;

   gl_FragColor = vec4(v_Color.rgb, 1);

   }

   """

   vs = np.array(pos) + (np.random.random((n,3)) - 0.5) * h/100

   color = np.tile(np.array((1.0,1.0,0.8)), (n,1))

   delay = np.float32(np.absolute(np.random.randn(n))) / 10

   tmax = (pow(v*v+2*a*h, 0.5)-v)/a + delay.max()

   m = wxgl.Model(wxgl.POINTS, vshader_src, fshader_src, sprite=True)

   m.set_vertex(a_Position, vs)

   m.set_color(a_Color, color)

   m.set_argument(a_Delay, delay)

   m.set_argument(u_Ts, lambda tn,gms,tms:(tms/1000)%cycle)

   m.set_argument(u_V, v)

   m.set_argument(u_A, a)

   m.set_argument(u_Tmax, tmax)

   m.set_mvp_matrix(u_MVPMatrix) # 设置模型矩阵、视点矩阵和投影矩阵

   return m, tmax

  def bomb_1(n, pos, start, a, cycle):

   """烟花爆炸模型

   n - 粒子数量

   pos - 位置

   start - 时间

   a - 下降加速度

   cycle - 循环周期

   """

   vshader_src = """

   #version 330 core

   in vec4 a_Position;

   in vec3 a_Data;

   uniform float u_Ts;

   uniform float u_Start;

   uniform float u_A;

   uniform mat4 u_MVPMatrix;

   out vec4 v_Color;

   out float v_Ts;

   void main() {

   float t = u_Ts - u_Start;

   if (t < 0) t = 0;

   float lat = radians((a_Data.x - 0.5) * 90);

   float lon = radians(a_Data.y * 360);

   float r = (a_Data.z * 0.3 + 0.7) * 0.3 * t * (1 + 0.3 * a_Position.z);

   float y = r * sin(lat) + a_Position.y - 0.5*u_A*t*t;

   float xz = r * cos(lat);

   float x = xz * cos(lon) + a_Position.x;

   float z = xz * sin(lon) + a_Position.z;

   gl_Position = u_MVPMatrix * vec4(x,y,z,a_Position.w);

   gl_PointSize = 3 * t;

   v_Ts = t;

   int i = gl_VertexID % 6;

   if (i == 0) v_Color = vec4(1,0,0,1);

   else if (i == 1) v_Color = vec4(0,1,0,1);

   else if (i == 2) v_Color = vec4(0,0,1,1);

   else if (i == 3) v_Color = vec4(1,1,0,1);

   else if (i == 4) v_Color = vec4(0,1,1,1);

   else v_Color = vec4(1,0,1,1);

   }

   """

   fshader_src = """

   #version 330 core

   in vec4 v_Color;

   in float v_Ts;

   void main() {

   if(v_Ts <= 0 v_Ts > 2) discard;

   vec2 temp = gl_PointCoord - vec2(0.5);

   float f = dot(temp, temp);

   if(f > 0.25) discard;

   //float alpha = v_Color.a * exp(1-30*f) * (4-v_Ts*v_Ts)/2;

   float alpha = v_Color.a * (1-4*f) * (4-v_Ts*v_Ts)/2;

   gl_FragColor = vec4(v_Color.rgb, alpha);

   }

   """

   vs = np.tile(np.array(pos), (n,1))

   data = np.float32(np.random.random((n,3)))

   m = wxgl.Model(wxgl.POINTS, vshader_src, fshader_src, sprite=True, opacity=False)

   m.set_vertex(a_Position, vs)

   m.set_argument(a_Data, data)

   m.set_argument(u_Start, start)

   m.set_argument(u_A, a)

   m.set_argument(u_Ts, lambda tn,gms,tms:(tms/1000)%cycle)

   m.set_mvp_matrix(u_MVPMatrix) # 设置模型矩阵、视点矩阵和投影矩阵

   return m

  def bomb_2(pos, start, texture, a, size, cycle):

   """烟花爆炸模型

   pos - 位置

   start - 时间

   texture - 纹理

   a - 下降加速度

   cycle - 循环周期

   """

   vshader_src = """

   #version 330 core

   in vec4 a_Position;

   uniform float u_Ts;

   uniform float u_Start;

   uniform float u_A;

   uniform float u_Size;

   uniform mat4 u_MVPMatrix;

   out float v_Ts;

   void main() {

   float t = u_Ts - u_Start;

   if (t < 0) t = 0;

   if (t < 2) gl_PointSize = t * u_Size/2 * (1 + 0.3 * a_Position.z);

   else gl_PointSize = u_Size * (1 + 0.3 * a_Position.z);

   gl_Position = u_MVPMatrix * vec4(a_Position.x, a_Position.y-0.5*u_A*t*t, a_Position.z, a_Position.w);

   v_Ts = t;

   }

   """

   fshader_src = """

   #version 330 core

   uniform sampler2D u_Fireworks;

   in float v_Ts;

   void main() {

   if(v_Ts <= 0 v_Ts > 2) discard;

   vec4 color = texture2D(u_Fireworks, gl_PointCoord);

   gl_FragColor = vec4(color.rgb, color.a*(4-v_Ts*v_Ts)/2);

   }

   """

   vs = np.array(pos).reshape(-1,3)

   m = wxgl.Model(wxgl.POINTS, vshader_src, fshader_src, sprite=True)

   m.set_vertex(a_Position, vs)

   m.set_argument(u_A, a)

   m.set_argument(u_Size,size)

   m.set_argument(u_Start, start)

   m.set_argument(u_Ts, lambda tn,gms,tms:(tms/1000)%cycle)

   m.add_texture(u_Fireworks, texture, wxgl.TEXTURE_2D, yflip=False)

   m.set_mvp_matrix(u_MVPMatrix) # 设置模型矩阵、视点矩阵和投影矩阵

   return m

  if __name__ == __main__:

   vs = np.array([[-1.5,2,1], [-1.5,0,1], [1.5,2,1], [1.5,0,1], [-1.5,2,-1], [-1.5,0,-1], [1.5,2,-1], [1.5,0,-1]])

   vs = vs[[0,1,2,3,0,2,1,3,4,5,6,7,4,6,5,7,0,4,1,5,2,6,3,7]]

   plt.figure(zoom=0.5, elev=10)

   plt.line(vs, color=(0,1,1,0), method=isolate) # 六面体线框,表示烟花燃放的空间

   # ------------------------------

   h, v, a, cycle = 1.7, 2.2, -1.2, 4

   for i, ch in enumerate(新春快乐):

   x = -1.5 + i

   m1, start = rise(n=300, pos=(x,0,1), h=h, v=v, a=a, cycle=cycle)

   m2 = bomb_1(200, (x,h,1), start, a=0.1, cycle=cycle)

   m3 = bomb_2((x,h,1), start, wxgl.text2image(ch, 96, (1,0,0)), a=0.1, size=100, cycle=cycle)

   plt.model(m1)

   plt.model(m2)

   plt.model(m3)

   # -------------------------------

   for i in range(20):

   x, z = (np.random.random()-0.5)*4, (np.random.random()-0.5)*2

   h, v, a = 1.5+(np.random.random()-0.5)*0.4, 2.2, -1.2

   cycle = np.random.randint(4, 7)

   m1, start = rise(n=300, pos=(x,0,z), h=h, v=v, a=a, cycle=cycle)

   m2 = bomb_1(200, (x,h,z), start, a=0.1, cycle=cycle)

   plt.model(m1)

   plt.model(m2)

   # -------------------------------

   for i in range(20):

   x, z = (np.random.random()-0.5)*4, (np.random.random()-0.5)*2

   h, v, a = 1.5+(np.random.random()-0.5)*0.4, 2.3, -1.2

   cycle = np.random.randint(4, 7)

   m1, start = rise(n=300, pos=(x,0,z), h=h, v=v, a=a, cycle=cycle)

   m2 = bomb_2((x,h,z), start, res/fw.png, a=0.1, size=300, cycle=cycle)

   plt.model(m1)

   plt.model(m2)

   plt.show()

  

  最终的效果如下面的gif所示。

  

  到此这篇关于Python OpenGL绘制一场烟花盛会的文章就介绍到这了,更多相关Python OpenGL烟花内容请搜索盛行IT软件开发工作室以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT软件开发工作室!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: