<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          臥槽!GPU里的生命游戲,居然還能這樣玩!

          共 2949字,需瀏覽 6分鐘

           ·

          2021-05-30 06:07

          簡單,優(yōu)雅,有極強的涌現(xiàn)性,又發(fā)人深省。這就是能令我盯著它發(fā)呆的"生命游戲"。今天練習在 GPU 里運行"生命游戲",文末有項目地址。

          生命游戲的規(guī)則

          生命游戲(Game of Life)是一類二維的元胞自動機,由 J.Conway 在1970年代設計。規(guī)則如下:

          1. 有一個二維網(wǎng)格,每個格子代表一個元胞。
          2. 格子有0和1兩種狀態(tài),對應元胞的"死"和"生"。
          3. 每個元胞有8個相鄰的元胞,元胞和其8個鄰居的當前時刻狀態(tài)決定了它下一時刻的狀態(tài)。
            • 如果元胞當前為"生",則僅當8個鄰居中有2個或3個為"生"時,該元胞保持"生",否則變?yōu)?死"
            • 如果元胞當前為"死",則僅當8個鄰居中有3個為"生"時,該元胞變?yōu)?生",否則保持"死"

          在GPU里運算

          生命游戲的規(guī)則很簡單,并且對并行計算非常友好,非常適合通過 GPU 進行運算和展現(xiàn)。本文使用 Cocos Creator 2.4.0,通過編寫shader實現(xiàn)基于 GPU 的生命游戲運算。

          流程

          整個過程涉及到3張紋理:表示網(wǎng)格初始狀態(tài)的紋理T和兩個 RenderTexture (分別命名為RTARTB)。 RTARTB會在運行時交替地計算自身的下一時刻狀態(tài)到對方紋理中。大致流程如下:

          設置紋理狀態(tài)

          // 禁用紋理動態(tài)合圖
          texture.packable = false;

          // 采樣坐標周期循環(huán),可以比較方便地實現(xiàn)元胞自動機的周期型邊界條件,不過要求紋理大小必須是2的冪
          texture.setWrapMode(cc.Texture2D.WrapMode.REPEAT, cc.Texture2D.WrapMode.REPEAT);

          // 使用最近距離采樣,避免出現(xiàn)插值
          texture.setFilters(cc.Texture2D.Filter.NEAREST, cc.Texture2D.Filter.NEAREST);

          狀態(tài)迭代

          根據(jù)規(guī)則,需要對當前位置和周圍8個鄰居的狀態(tài)進行采樣。對鄰近位置進行采樣需要根據(jù)紋素大小進行偏移,這里命名為dxdy,通過 uniform 變量傳入 shader。 dx=1.0/widthdy=1.0/height

          // 統(tǒng)計8個鄰居的狀態(tài),計算結束后sum的范圍是[0.0, 8.0]
          vec4 sum = vec4(0.);
          vec4 d = vec4(dx, dy, -dy, 0.);
          sum += texture(texture, uv-d.xy);   // 即uv + (-dx, -dy)處采樣
          sum += texture(texture, uv-d.xw);   // 即uv + (-dx, 0.)處采樣
          sum += texture(texture, uv-d.xz);   // 即uv + (-dx, +dy)處采樣
          sum += texture(texture, uv+d.wz);   // ...以此類推
          sum += texture(texture, uv+d.wy);
          sum += texture(texture, uv+d.xz);
          sum += texture(texture, uv+d.xw);
          sum += texture(texture, uv+d.xy);

          判斷sum是否在某個區(qū)間內,可以將兩個step()函數(shù)疊加進行判斷。

          // 如果元胞當前為"生",則僅當8個鄰居中有2個或3個為"生"時,該元胞保持"生",否則變?yōu)?死"
          // 只有當sum = 2或者3時,oneCase的值是1.0
          vec4 oneCase = step(vec4(1.9), sum) * step(sum, vec4(3.1));

          // 如果元胞當前為"死",則僅當8個鄰居中有3個為"生"時,該元胞變?yōu)?生",否則保持"死"
          // 只有當sum = 3時,zeroCase的值是1.0
          vec4 zeroCase = step(vec4(2.9), sum) * step(sum, vec4(3.1));

          根據(jù)當前元胞自身狀態(tài)進行分支選擇

          vec4 col = texture(texture, uv);
          col = mix(zeroCase, oneCase, col);

          初始狀態(tài)

          不同的初始狀態(tài)決定了生命游戲的后續(xù)發(fā)展,通過精心設計初始狀態(tài),可以產生狀態(tài)循環(huán)、整體平移等神奇的表現(xiàn)。
          這里直接搬運網(wǎng)絡上的現(xiàn)成的模型翻譯成RenderTexture作為初始狀態(tài),參考了 https://funnyjs.com/jspages/game-of-life.html

          并行的生命游戲

          表示元胞的"生"、"死"不需要用完一個vec4變量,只需要一個分量即可。所以當我們把初始狀態(tài)紋理的 RGB 通道解耦,讓它們獨立取0或1后,我們就得到了3個生命游戲的初始狀態(tài)紋理,shader 代碼不需要改動就可以支持3個生命游戲的并行演算(A通道也利用上就是4個)。

          代碼 & Demo


          源碼地址:
          http://store.cocos.com/app/detail/2895 (點擊閱讀原文可跳轉)

          參考

          https://zhuanlan.zhihu.com/p/39451507
          http://micro.ustc.edu.cn/CompPhy/lecturenote/comp_sun_3_4.pdf
          https://funnyjs.com/jspages/game-of-life.html



          瀏覽 73
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久这里只有精品99 | 手机av在线 | 麻豆的视频高清在线观看完整 | 操碰97人人操 | 亚洲中文av |