<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>

          Cocos Shader 基礎(chǔ)入門(一):WebGL 著色器與 GLSL 著色器語言基礎(chǔ)

          共 7005字,需瀏覽 15分鐘

           ·

          2021-09-20 16:51

          引言:

          Shader(可編程著色器)是用來實現(xiàn)圖像渲染的可編輯程序。它并不是簡單的計算機應(yīng)用,要想真正地掌握 Shader,需要對圖形學(xué)、圖形 API、GPU、顯卡等都有個宏觀概念。而對大多數(shù)游戲開發(fā)者來說,“快速”入門又是當下的迫切需求。因此,Cocos 布道師放空整理了一個 Cocos Shader 基礎(chǔ)系列教程(8期入門+2期擴展),介紹 Shader 的基礎(chǔ)知識以及在 Cocos Creator 里的應(yīng)用,帶一些小伙伴快速入門 Shader 編寫。


          在 Cocos Shader 開始之前,我會先介紹一些 Shader 基礎(chǔ)知識,從最淺顯的部分開始,揭開 Shader 的神秘面紗。本次講解采用的渲染引擎是 WebGL,首先來了解一些渲染管線知識。


          CPU 與 GPU 的區(qū)別


          在介紹 WebGL 之前先來了解一些前置知識,也就是 CPU 和 GPU。


          CPU 和 GPU 都屬于處理單元,但是結(jié)構(gòu)不同。形象來說,CPU 有點像大型的傳輸管道,等待處理的任務(wù)只能依次通過,所以 CPU 處理任務(wù)的速度取決于處理單個任務(wù)的時間。又由于 CPU 內(nèi)部結(jié)構(gòu)異常復(fù)雜,能夠處理大量的數(shù)據(jù)和邏輯判斷,所以處理一些大型任務(wù)是足夠的。但是處理圖像卻不在行,因為處理圖像的邏輯通常不復(fù)雜,但是由于一幅圖像是有成千上萬的像素點構(gòu)成,每個像素的處理都是一個任務(wù),如果由 CPU 處理,那簡直就是大材小用。因此就需要用到 GPU。GPU 由大量的小型處理單元構(gòu)成,處理能力沒 CPU 強大,但勝在數(shù)量多,并且能夠并行處理。


          渲染管線


          在渲染過程中需要 CPU 和 GPU 之間的通力合作。CPU 如同進貨的卡車不斷地將要處理的數(shù)據(jù)丟給 GPU,GPU 工廠調(diào)動一個個如工人一般的計算單元對這些數(shù)據(jù)進行簡單的處理,最后組裝出產(chǎn)品——圖像。


          什么是 WebGL?


          WebGL 是一種 3D 繪圖標準,它的本質(zhì)是 JavaScript 操作 OpenGL 接口,所以 WebGL 是在 OpenGL 的基礎(chǔ)上做了一層封裝,底層本質(zhì)還是 OpenGL。利用 WebGL 可以根據(jù)你的代碼繪制出點、線和三角形。任何復(fù)雜的場景都可以組合使用點、線和三角形實現(xiàn)。WebGL 運行在 GPU 中,因此需要使用能夠在 GPU 上運行的程序。這樣的程序需要成對提供,每對方法中都包含一個頂點著色器和一個片斷著色器,并且使用 GLSL 語言(GL 著色語言)編寫。每對組合起來稱作一個 program(著色程序)。


          在 WebGL 中,任何事物都處于 3D 空間中,但最終輸出呈現(xiàn)給觀眾的往往是屏幕或者窗口這種 2D 像素,因此,在渲染引擎底層大部分工作都是把 3D 坐標轉(zhuǎn)變成適應(yīng)屏幕的 2D 像素。3D 坐標轉(zhuǎn) 2D 的處理過程是由 WebGL 的圖形渲染管線處理,它的主要傳輸流程分為兩步:


          1. 將 3D 坐標轉(zhuǎn)換成 2D 坐標

          2. 把 2D 坐標轉(zhuǎn)變成實際有顏色的像素


          這兩個流程又被劃分為幾個階段處理,每個階段都會把前一個階段的輸出作為輸入。



          如上圖所見,圖形渲染管線包含多個階段,在轉(zhuǎn)換頂點數(shù)據(jù)到最終像素的這個過程中,每個階段都將處理各自的職責(zé)部分。接下來,簡單介紹管線各個階段的功能:


          • 頂點數(shù)據(jù):頂點數(shù)據(jù)用來為后面的頂點著色器等階段提供處理的數(shù)據(jù),是渲染管線的數(shù)據(jù)主要來源。送入到渲染管線的數(shù)據(jù)包括頂點坐標、紋理坐標、頂點法線和頂點顏色等頂點屬性,WebGL 根據(jù)渲染指令傳遞對應(yīng)的圖元信息(常見圖元包括點、線和面)。


          • 頂點著色器:頂點著色器的主要功能是坐標轉(zhuǎn)換。把一個單獨的頂點作為輸入,并對頂點進行從局部坐標到裁剪坐標的變換,其實就是將游戲里操作的 3D 坐標轉(zhuǎn)換成另一種 3D 坐標。



          • 圖元裝配:圖元裝配階段將頂點著色器輸出的所有頂點作為輸入,根據(jù)指定的指令(點、線或面)將所有的點裝配成指定圖元的形狀。例如:提供兩個頂點時,是否要將兩個頂點連接成一條線段,以及多條線段之間是否需要連接。



          • 光柵化:如何使用頂點和裝配的方式將矩形表示在屏幕上,就是光柵化的過程。遍歷所有的像素為止,依次判斷它們是否落入了組裝的圖形內(nèi),如果在圖形內(nèi),則對該像素進行下一步操作(著色)。還會對非頂點的位置進行插值處理,賦予每個像素其他的信息。


          • 片段著色器:片段著色器主要是對圖形內(nèi)的片元進行著色處理,這里也是高級效果產(chǎn)生的階段。通常,片段著色器包含 3D 場景的數(shù)據(jù)(比如光照、陰影、光的顏色等等),這些數(shù)據(jù)可以被用來計算最終像素的顏色。


          • 測試與混合:在所有對應(yīng)顏色值確定以后,最終的對象將會被傳到最后一個階段,叫做 Alpha 測試與混合階段。這個階段檢測片段的對應(yīng)的深度,用以判斷這個像素在其它物體的前面還是后面、決定是否應(yīng)該丟棄。這個階段也會檢查透明度 alpha 值,并對物體進行混合。所以,即使在片段著色器中計算出了一個像素輸出的顏色,在渲染多個三角形的時候最后的像素顏色也可能完全不同。


          可以看出,圖形渲染管線非常復(fù)雜,簡單總結(jié)一下:WebGL 在 GPU 上的工作基本上分為兩部分,第一部分是將頂點數(shù)據(jù)轉(zhuǎn)換到裁剪空間坐標, 第二部分是基于第一部分的結(jié)果繪制像素點。接下來,我們一步步實踐,加深對這塊的理解。


          GLSL 語言基礎(chǔ)


          GLSL 是為圖形計算量身定制的,它包含一些針對向量和矩陣操作的特性。一個著色器通常包含輸入輸出變量、uniform 和 main 函數(shù)。每個著色器的入口都是 main 函數(shù),在 main 函數(shù)中處理所有輸入變量,并將結(jié)果輸出到輸出變量中。


          一個常見頂點/片段著色器如下:

          // 頂點著色器

          // 輸入屬性 attribute 變量類型 vec4 變量名 a_position
          attribute vec4 a_position;
          attribute vec2 a_uv;
          attribute vec4 a_color;

          // 輸入輸出屬性
          varying vec4 v_color;
          varying vec2 v_uv;

          // 每一個著色器都有 main 函數(shù),這是與 WebGL 對接的接口
          void main() {
              // 基礎(chǔ)賦值語句
              v_color = a_color;
              v_uv = a_uv;
              // 內(nèi)置變量 gl_Position
              gl_Position = a_position;
          }

          // 片段著色器

          // lowp 精度
          varying lowp vec4 v_color;
          varying highp vec2 v_uv;

          uniform sampler2D mainTexture;

          void main(void) {
              vec4 o = texture2D(mainTexture, v_uv);
              o *= v_color
              gl_FragColor = o;
          }


          此處會列舉一些變量、修飾符和常見用法,更多使用方式可以參考下方的 GLSL 詳解(基礎(chǔ)篇),里面的內(nèi)容寫的還是很詳細的,當然,有條件的同學(xué)可以直接上 GLSL 官網(wǎng)文檔查看。


          1

          變量和變量類型



          常用的幾種使用方式如下:

          // 標量
          float myFloat = 1.0;
          bool myBool = bool(myFloat); // float -> bool

          // 向量
          vec4 myVec4 = vec4(1.0); // myVec4 = {1.0, 1.0, 1.0, 1.0}
          vec2 myVec2 = vec2(1.0, 0.5);  // myVec2 = {1.0, 0.5}
          vec2 temp = vec2(myVec2); // temp = {1.0, 0.5}
          myVec4 = vec4(myVec2, temp, 0.0);
          // 向量和矩陣的計算是逐分量進行的,因此,也可以采用下面這兩個個方法
          vec3 myVec3a = myVec2.xyx; // 通過分量訪問符 myVec3a = {1.0, 0.5, 1.0}
          vec3 myVec3b = vec3(myVec2[0], myVec2[1], myVec2[2]); // 通過數(shù)組 myVec3b = {1.0, 0.5, 1.0}

          // 矩陣
          mat3 myMat3 = mat3(1.0, 0.0, 0.0,  // 第一列
                             0.0, 1.0, 0.0,  // 第二列
                             0.0, 1.0, 1.0); // 第三列
          mat4 myMat4 = mat4(1.0) // myMat4 = {1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0}

          // 向量、標量和矩陣的交互使用
          vec3 v, u;
          float f;
          v = u + f;
          // 等價于 v.x = u.x + f;
          // v.y = u.y + f;
          // v.z = u.z + f;

          mat3 m;
          u = v * m; 
          // 等價于 u.x = m[0].x * v.x + m[1].x * v.y + m[2].x * v.z;
          // u.y = m[0].y * v.x + m[1].y * v.y + m[2].y * v.z;
          // u.z = m[0].z * v.x + m[1].z * v.y + m[2].z * v.z;


          2

          限定符


          2.1  存儲限定符



          使用方法:

          attribute vec4 a_position;
          varying vec4 v_color;


          2.2  參數(shù)限定符


          vec4 myFunc(inout float myFloat, // 輸入輸出參數(shù)
                      out vec4 myVec4,   // 輸出
                      mat4 myMat4);    // 輸入?yún)?shù)


          2.3  精度限定符



          使用方法:

          // 預(yù)先聲明
          precision highp float;
          precision mediump int;

          // 指定變量聲明
          varying lowp vec4 v_color;


          狀態(tài)機


          在 WebGL 上,大多數(shù)元素都可以用狀態(tài)來描述,比如:是否啟用了光照、是否啟用了紋理、是否啟用了混合、是否啟用了深度測試等。通常 WebGL 會執(zhí)行默認狀態(tài),除非我們調(diào)用相關(guān)接口改變它,比如:gl.Enablexxx 或者 gl.Disablexxx。


          上下文(Context)


          WebGL 需要依賴 canvas 這個載體獲取對應(yīng)的繪圖上下文,通過繪圖上下文調(diào)用相對應(yīng)的繪圖 API,包括上面提到的各種狀態(tài)切換。每一個對象的繪制,都需要先設(shè)置一系列狀態(tài)值,然后通過調(diào)用 "gl.drawArrays" 或 "gl.drawElements" 運行一個著色方法對,使得你的著色器對能夠在 GPU 上運行。WebGL 渲染上下文創(chuàng)建如下:

          // 定義一個 canvas 元素
          var gl = canvas.getContext("webgl");
          if(!gl){
              // 你不能使用 WebGL
          }




          本章到此主要介紹一些 WebGL 的基礎(chǔ)知識,包括渲染管線流程、渲染使用語言等。下一章開始介紹繪制流程,重點內(nèi)容包括頂點著色器和片元著色器的作用


          內(nèi)容參考:

          1. WebGL 基礎(chǔ):

          https://webglfundamentals.org/webgl/lessons/zh_cn/webgl-fundamentals.html

          2. WebGL API 對照表:

          https://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf

          3. OpenGL 中文文檔:

          https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/

          4. GLSL 詳解:

          https://colin1994.github.io/2017/11/11/OpenGLES-Lesson04/

          5. 細說圖形渲染管線:

          https://zhuanlan.zhihu.com/p/79183044


          往期精彩

          瀏覽 134
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  激情黄色毛片 | 黄片视频软件 | 啪啪啪啪网站 | 哪里可以看日本黄色电影 | www综合伊人 |