中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么用Python?OpenGL繪制一場煙花盛會

發布時間:2022-02-07 10:35:54 來源:億速云 閱讀:144 作者:iii 欄目:開發技術

本文小編為大家詳細介紹“怎么用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 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

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. 綻放的煙花

只要理解了煙花升空的代碼,很容易寫出煙花在空中爆炸的著色器程序。下面的代碼除了煙花升空的著色器,還提供了兩種煙花爆炸的著色器,其中用到了一個紋理圖片,可直接下載下面這張圖使用。

怎么用Python?OpenGL繪制一場煙花盛會

如果將上面的紋理圖片替換成文字,就可以在煙花爆炸的瞬間顯示出文字了。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繪制一場煙花盛會”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

永胜县| 高密市| 化德县| 札达县| 玉田县| 九龙坡区| 通州市| 泾川县| 茂名市| 凤城市| 乌鲁木齐市| 兴安盟| 石狮市| 西峡县| 望都县| 乌拉特中旗| 德令哈市| 儋州市| 临武县| 湟源县| 隆回县| 朝阳市| 百色市| 浪卡子县| 正蓝旗| 滁州市| 红安县| 新宁县| 淅川县| 汪清县| 横峰县| 保康县| 菏泽市| 大同县| 思茅市| 霸州市| 浦江县| 射阳县| 鄂尔多斯市| 沙雅县| 健康|