• <nav id="yisao"><rt id="yisao"></rt></nav>
  • Cocos Creator 3D 材質系統:曲面效果如何實現?

    ?前不久發布的 Cocos Creator 1.0.2 版本中正式加入了對 OPPO 小游戲、vivo 小游戲以及華為快游戲平臺的支持,在諸多 Creator 3D 制作的小游戲案例中,《豬豬俠:極速狂飆》已上線 OPPO 小游戲平臺。

    這款休閑跑酷小游戲,采用了曲面材質效果來使跑酷賽道更加多變有趣,今日,Cocos 引擎開發工程師 ChiaNing 將為各位開發者來解析這種曲面效果的實現思路和方案,在閱讀完本文之后,大家便可以將這種效果應用在自己的游戲中。

    使用背景

    在固定背后視角的跑酷游戲中,玩家面對的始終是前方布滿障礙的賽道,除去有趣的障礙設計可以一直吸引玩家的注意外,許多游戲還會添加一些視覺效果來使游戲畫面看起來更豐富有趣,比如今天我們要分享的這款《豬豬俠:極速狂飆》就采用了曲面的效果使得賽道看起來更多變,也更有立體感縱深感。

    那么,這樣的曲面效果在 Cocos Creator 3D 中是如何實現的呢?

    實現方案分析

    要實現曲面的效果,我們有幾種方案可選擇:

    1. 直接使用曲面模型

    這是最直觀最容易想到的實現方案,從模型層面直接將效果做好,省去了其他處理,但這種方案也存在著很多嚴重的問題:

    (1)模型復用不便,模型生成時的狀態幾乎決定了它的使用場合,這對于游戲開發中需要大量復用資源以減小包體來說有嚴重的問題。

    (2)對于跑酷游戲這種物理需求并不復雜的游戲來說,大部分的游戲邏輯都可以直接通過計算直接完成而并不需要依賴物理引擎實現,對于正常的模型來說,規則的形狀對于邏輯實現是很友好的,但是啟用曲面模型就會對這種計算帶來很多困難,幾乎只能通過使用物理引擎來實現,過多的物理計算對性能是會有較大的影響的。

    包體不友好,性能不友好,異型模型還會對制作帶來麻煩,對于只是為了實現顯示效果來說,這些損耗得不償失。

    2. 使用材質系統實現

    我們需要明白一點,要實現的曲面的效果,實際上影響的只有顯示效果,與其他的任何系統是不相關的,它不應當影響到其他無關的模塊,既然只想改變顯示,那采用材質系統相較于采用曲面模型的方案有著諸多好處:

    (1)不必使用物理引擎,簡單的物理效果可以通過計算來實現,效率更優。

    (2)模型可復用,想要實現不同的彎曲效果也很方便,只要使用帶有曲面效果的不同參數的材質即可實現同一模型的不同效果。相較于方案一的多重模型來說,只需要幾個材質即可解決問題。

    (3)參數可配置,可以通過參數調節來得到不同的效果。

    分析看來,相較于直接使用曲面模型的方案來說,使用材質系統實現的方案優勢很明顯,沒有額外的開銷,也沒有太大的包體負擔。

    綜上所述,使用材質系統實現更能滿足我們的需求,因此采用材質系統來實現這個效果。

    方案思路分析

    從需求來看,我們的目的是實現一個與我們的觀察點相關的模型變形,既然只是變形,并不涉及到顏色的變化和處理,那么需要處理的就只有頂點著色器部分,并不涉及片段著色器。對于不太清楚渲染管線各個階段的讀者,可以參考 [LearnOpenGL]的渲染管線介紹。

    在 Shader 中,通過頂點著色器即可完成對模型頂點位置的操作。

    明確了是對頂點位置進行操作后,我們將攝像機所在的點定為原點。

    由于我們的攝像機是固定在人物背后,且賽道始終保持向 Z 軸負方向延伸,所以可以將模型與攝像機的 Z 軸方向的距離看作函數的輸入值,想要得到曲面的效果,模型的點的變化規律如下:

    • 距離原點越遠的點產生的偏置值越大(函數在區間內為增函數)
    • 距離原點越遠的點偏置的變化速度越快(函數的導數為一次函數)

    由上述兩條規律不難得出,二次函數的變化規律與我們想要實現的曲面效果的規律契合,所以我們的頂點著色器的運算為一個關于頂點位置 Z 值的二次函數運算。

    我們剛剛得出的規律是建立在一個特定空間下的,即以攝像機為原點的空間,這個空間正是空間變換中的觀察空間階段,所以我們之后對頂點的操作正是在這個空間中進行才能夠得到正確的結果。

    材質系統簡介

    Cocos Creator 3D 提供了完備的材質系統,基于這套材質系統,我們能夠很方便地在引擎中創建使用編輯材質,并且在場景預覽窗口能夠隨時觀察到材質更改所帶來的變化。

    在 Cocos Creator 3D 編輯器中與材質系統相關的資源有兩種,分別為:

    Effect 資源

    此類型資源為符合 Cocos Effect 語法標準的渲染流程描述文件,由 YAML 格式的流程控制清單和基于 GLSL 300 ES 語法的 Shader 片段共同組成。

    Material 資源

    此資源可看做是 Effect 資源在場景中的資源實例,其本身除了 Effect 資源的引用外,還包括很多可配置參數以決定 Material 的狀態。在實際使用中,我們的模型是需要使用 Material 資源的,這樣就可以實現使用同一個 Effect 但參數不同以實現不同效果的需求了。

    材質的使用也非常的方便,在 Cocos Creator 3D 編輯器的資源管理器中右鍵即可新建出 Effect 資源和 Material 資源。

    在 Material 資源可選擇需要使用的 Effect 還可對其他參數進行配置,完成配置并保存后,選中需要使用材質的模型,選中需要的 material 或者直接將 material 拖入框中即可完成材質的設置。

    具體詳盡的材質介紹和參數表請參看官方文檔[材質系統]。

    具體實現

    思路已經很清晰了,那么現在開始著手實現 Shader。下面是具體的實現步驟:

    1、啟動 Cocos Creator 3D 編輯器(以下簡稱編輯器),為實驗方便,使用最簡單的場景即可,新建場景后,在場景編輯器中新建一個 Plane 模型,之后以此對象作為查看 Shader 效果的對象。

    2、在編輯器的資源管理器中右鍵新建 Effect,將其命名為 curved 或者符合要求的名字。

    3、這時新建的 Effect 文件為編輯器內置的 Effect 模板,其包含了最基礎的 shader 結構,我們需要在這個基礎上添加我們需要的功能,關于 Effect 的具體介紹請參看我們的[材質 Effect 文檔],在里我只對我們需要的更改做出介紹。

    4、先來看 CCEffect 部分:

        CCEffect %{
          techniques:
          - name: opaque
            passes:
            - vert: general-vs:vert # builtin header
              frag: unlit-fs:frag
              properties: &props
                mainTexture:    { value: white }
                mainColor:      { value: [1, 1, 1, 1], editor: { type: color } }
          - name: transparent
            passes:
            - vert: general-vs:vert # builtin header
              frag: unlit-fs:frag
              blendState:
                targets:
                - blend: true
                  blendSrc: src_alpha
                  blendDst: one_minus_src_alpha
                  blendSrcAlpha: src_alpha
                  blendDstAlpha: one_minus_src_alpha
              properties: *props
        }%
    • 在默認的 Effect 模板中,我們需要更改的是 vert 字段所使用的 Shader 片段,默認模板中提供的 general-vs:vert 是內置的頂點著色器,所以我們需要將其替換為我們即將實現的頂點著色器的名字(暫定為 unlit-vs).
    • 接下來,需要對 properties 部分進行修改,property 列表將會將屬性暴露在編輯器面板上方便我們的編輯和更改。
    • 此時需要決定哪些數據是需要作為 uniform 傳入 shader 中對效果做出影響的了,結合之前分析的需求:需要有一個決定模型點在各個分量軸上偏置值的偏置位置信息,我們使用一個 vec4 來存儲這個偏置值(allOffset);需要有一個決定偏置變化的系數的值,使用一個 float 即可(dist);還可以添加模型的主貼圖等(mainTexture)
    • 經過以上更改之后,Effect 的 CCEffect 部分看起來是這個樣子的:
          CCEffect %{
            techniques:
            - name: opaque
              passes:
              - vert: unlit-vs:vert
                frag: unlit-fs:frag
                properties: &props
                  mainTexture:  { value: grey         }
                  allOffset:    { value: [0, 0, 0, 0] }
                  dist:         { value: 1            }
            - name: transparent
              passes:
              - vert: unlit-vs:vert
                frag: unlit-fs:frag
                depthStencilState:
                  depthTest: true
                  depthWrite: false
                blendState:
                  targets:
                  - blend: true
                    blendSrc: src_alpha
                    blendDst: one_minus_src_alpha
                    blendDstAlpha: one_minus_src_alpha
                properties: *props
          }%

    5、由于默認的 Effect 模板中使用了內置的頂點著色器,所以這里需要實現自己的頂點著色器,可以參考內置的 builtin-unlit 的實現來編寫此段 shader:

    • 添加需要的 uniform :
               uniform Constants {
                  vec4 allOffset;
                  float dist;
              }; 
    • 編寫入口函數:vert
    • 按照引擎要求對接骨骼動畫和數據解壓,直接在開頭調用 CCVertInput 工具函數。
    • 模型資源在場景中可能出現很多重復的,這樣就需要對模型進行動態合批,對接引擎的動態合批流程,在包含 cc-local-batch 頭文件后,通過 CCGetWorldMatrix 函數獲取世界矩陣。
               vec4 position;
              CCVertInput(position);
    
              highp mat4 matWorld;
              CCGetWorldMatrix(matWorld); 
    • 在分析時提到,需要在觀察空間下對頂點進行處理,所以需要將坐標轉換到觀察空間下。曲面效果是和 Z 坐標直接相關的,所以系數也是直接影響 Z 坐標的。
    • dist 系數為影響變化的系數,所以在和 vpos.z 的運算時,可以使用乘法也可以使用除法,但這個改變會直接影響 dist 的取值,所以在決定是使用除法還是乘法后,需要對值進行對應修改,且注意使用除法時 dist 的值不可為 0。
    • 對于各軸分量的修改,需要 allOffset 參與運算然后造成影響,此處的 zOff 的平方運算即為分析中的二次函數符合變化規律的實現。
    • 在處理完成之后,按照正常的變換邏輯繼續將觀察空間通過投影矩陣變換為裁剪空間下的坐標之后繼續傳遞給片段著色器即可。
              highp vec4 vpos = cc_matView * matWorld * position;
              highp float zOff = vpos.z / dist;
              vpos += allOffset * zOff * zOff;
              highp vec4 pos = cc_matProj * vpos;
    
              v_uv = a_texCoord;
              return pos; 

    6、對于片段著色器,我們并未做特殊的操作,所以直接使用默認提供的就可以。

    7、最終的 effect 如下:

         CCEffect %{
          techniques:
          - name: opaque
            passes:
            - vert: unlit-vs:vert
              frag: unlit-fs:frag
              properties: &props
                mainTexture:  { value: grey         }
                allOffset:    { value: [0, 0, 0, 0] }
                dist:         { value: 1            }
          - name: transparent
            passes:
            - vert: unlit-vs:vert
              frag: unlit-fs:frag
              depthStencilState:
                depthTest: true
                depthWrite: false
              blendState:
                targets:
                - blend: true
                  blendSrc: src_alpha
                  blendDst: one_minus_src_alpha
                  blendDstAlpha: one_minus_src_alpha
              properties: *props
        }%
    
        CCProgram unlit-vs %{
          precision highp float;
          #include <cc-global>
          #include <cc-local-batch>
          #include <input>
    
          in vec2 a_texCoord;
          out vec2 v_uv;
    
          uniform Constants {
            vec4 allOffset;
            float dist;
          };
    
          highp vec4 vert () {
            vec4 position;
            CCVertInput(position);
    
            highp mat4 matWorld;
            CCGetWorldMatrix(matWorld);
    
            highp vec4 vpos = cc_matView * matWorld * position;
            highp float zOff = vpos.z / dist;
            vpos += allOffset * zOff * zOff;
            highp vec4 pos = cc_matProj * vpos;
    
            v_uv = a_texCoord;
            #if FLIP_UV
              v_uv.y = 1.0 - v_uv.y;
            #endif
            return pos;
          }
        }%
    
        CCProgram unlit-fs %{
          precision highp float;
          #include <output>
    
          in vec2 v_uv;
          uniform sampler2D mainTexture;
    
          vec4 frag () {
            vec4 o = vec4(1, 1, 1, 1);
    
            o *= texture(mainTexture, v_uv);
    
            return CCFragOutput(o);
          }
        }% 

    8、在完成了 effect 之后,我們可以在編輯器中新建一個材質,在材質的 Effect 中選擇剛剛完成的 curved 之后傳入想要的貼圖,填入 dist 和 AllOffset 參數,保存之后將這個材質賦予剛剛提到的 plane 對象,調整參數可以看到我們的片面就能出現偏置效果了,移動攝像機可看到偏置效果是與頂點距離攝像機的距離相關的:

    9、請注意,Shader 的參數與模型的尺寸是相關的,上圖所示效果是在 dist 為 100,AllOffset 的 Y 值為 10 時的效果,各位開發者可嘗試不同的組合來達到想要的效果。

    10、似乎上圖的效果還不是太直觀,所以我用一些建筑模型和一些路面模型簡單搭建了一段賽道來模擬游戲可能會出現的場景。建議最好是能夠顯示出縱深效果的連續模型段,更能顯示出效果,當然這個效果并不只限于 Y 軸方向,還可以同時滿足 X 軸方向的偏置需求,下圖所示即為 Dist 為 100,X 為 -20,Y 為 -10 時的效果圖:

    總結

    相信各位對 [ShaderToy] 并不陌生,之后我們將提供從 ShaderToy 中遷移 Shader 的方法,海量 Shader 等你來學習!目前在我們的[官方案例倉庫]的 demo02 中,已經實現了一個遷移好的場景案例(ShaderToy),感興趣的小伙伴們趕快去試試吧!

    有很多小伙伴在社區分享了炫酷的材質效果,在這里感謝 @yans 做出的分享,歡迎有想法的開發者多做分享,共同促進社區成長。

    以上就是我今天帶來的材質系統案例分享,希望通過這個簡單的案例為各位提供一個了解材質系統的入口。材質系統功能十分豐富,能夠實現的效果也是多種多樣的,各位快快打開腦洞,用 Cocos Creator 3D 來實現各種炫酷的效果吧!

    歡迎小伙伴們繼續通過論壇、GitHub、Cocos 企業服務等渠道向我們提交 Cocos Creator 3D 使用反饋!

    Cocos Creator 3D 下載:

    http://www.cocoscvp.com/creator3d

    Cocos 中文社區:

    https://forum.cocos.org/c/3D

    3D 特別專題  

    模塊解析 | Cocos Creator 3D 材質系統 

    模塊解析 | Cocos Creator 3D 物理系統  

    案例分享 | 《彈彈樂》3D 完整開發流程

    案例分享 | 《快上車》3D 技術實現方案

    技術教程 | 從投籃小游戲入門 Creator 3D 開發

    技術教程 | Cocos Creator 3D 零基礎入門

    技術教程 | Cocos Creator 3D 螞蟻莊園系列

    技術教程 | Cocos Creator 3D 素材獲取

    版本動態 | Cocos Creator 3D 夢想再起航

    版本動態 | Cocos Creator 3D v1.0 正式發布

    版本動態 | Cocos Creator 3D v1.0.1 正式發布

    女人脱裤子让男生桶爽免费看,久青草无码视频在线播放,精品国产人成亚洲区,久久精品国产亚洲一区二区