文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

怎么用Python OpenGL绘制一场烟花盛会

2023-06-29 01:30

关注

本文小编为大家详细介绍“怎么用Python OpenGL绘制一场烟花盛会”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么用Python OpenGL绘制一场烟花盛会”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

1. 安装WxGL

WxGL是一个基于PyOpenGL的三维数据可视化库,以wx为显示后端,提供Matplotlib风格的交互式应用方式。WxGL也可以和wxPython无缝结合,在wx的窗体上绘制三维模型。使用pip命令即可快速安装WxGL及其所依赖的其他模块。

pip install wxgl

2. 快速体验

下面这几行代码,绘制了一个中心在坐标原点半径为1的纯色圆球。忽略模块名的话,这些代码和Matplotlib的风格是完全一致的。

>>> import wxgl.wxplot as plt>>> plt.uvsphere((0,0,0), 1, color='cyan')>>> plt.title('快速体验:$x^2+y^2=1$')>>> plt.show()

怎么用Python OpenGL绘制一场烟花盛会

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

>>> 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)%360),))>>> plt.show()

勾选“屏幕录制”,点击“播放”按钮,即可保存为gif文件或mp4/avi格式的视频文件。

怎么用Python OpenGL绘制一场烟花盛会

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

怎么用Python OpenGL绘制一场烟花盛会

3. 编写自己的着色器

WxGL不仅提供了线段、散点、曲面、三维等值面等一系列绘图函数,还支持用户定制着色器程序,以实现更复杂的功能。下面这个例子,用粒子技术模拟了烟花升空的过程。

# -*- coding: utf-8 -*-import numpy as npimport wxglimport wxgl.wxplot as pltdef 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 mvs = 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. 绽放的烟花

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

怎么用Python OpenGL绘制一场烟花盛会

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

# -*- coding: utf-8 -*-import numpy as npimport wxglimport wxgl.wxplot as pltdef 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, tmaxdef 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 mdef 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 mif __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绘制一场烟花盛会”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯