three.js 著色器材質之初識著色器

郭先生的部落格發表於2020-08-03

說起three.js,著色器材質總是繞不過的話題,今天郭先生就說一說什麼是著色器材質。著色器材質是很需要靈感和數學知識的,可以用簡短的程式碼和繪製出十分豐富的影像,可以說著色器材質是脫離three.js的另一塊知識,因此它十分難講,我們只能在一個一個案例中逐漸掌握著色器語言的使用技巧。

1. 什麼是著色器材質

著色器材質(ShaderMaterial)是一個用GLSL編寫的小程式 ,在GPU上執行。它能夠提供 materials 之外的效果,也可以將許多物件組合成單個Geometry或BufferGeometry以提高效能。

2. 著色器材質的變數

每個著色器材質都可以指定兩種不同型別的shaders,他們是頂點著色器和片元著色器(Vertex shaders and fragment shaders)。

  • 頂點著色器首先執行; 它接收attributes, 計算/操縱每個單獨頂點的位置,並將其他資料(varyings)傳遞給片元著色器。
  • 片元(或畫素)著色器後執行; 它設定渲染到螢幕的每個單獨的“片元”(畫素)的顏色。

shader中有三種型別的變數: uniforms, attributes, 和 varyings

  • Uniforms是所有頂點都具有相同的值的變數。 比如燈光,霧,和陰影貼圖就是被儲存在uniforms中的資料。 uniforms可以通過頂點著色器和片元著色器來訪問。
  • Attributes 與每個頂點關聯的變數。例如,頂點位置,法線和頂點顏色都是儲存在attributes中的資料。attributes 只 可以在頂點著色器中訪問。
  • Varyings 是從頂點著色器傳遞到片元著色器的變數。對於每一個片元,每一個varying的值將是相鄰頂點值的平滑插值。

注意:在shader 內部,uniforms和attributes就像常量;你只能使用JavaScript程式碼通過緩衝區來修改它們的值。

3. 著色器材質的使用

上面說了每個著色器材質都可以指定兩種不同型別的shaders,不過如果我們不去指定這兩個shaders而直接使用也不會報錯,因為ShaderMaterial已經定義了預設的頂點著色器和片元著色器,他們的程式碼是這樣的。

//頂點著色器程式碼
void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
//片元著色器程式碼
void main() {
    gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
}

這裡的projectionMatrix、modelViewMatrix和position都是three為我們設定好的變數,可以直接拿來用,前兩個變數我們之前已經說了,而position就是每一個頂點的座標值,當著色器程式碼執行時,會迴圈執行gl_Position和gl_FragColor設定頂點位置,和顏色插值。並且我們最終要設定的就是gl_Position和gl_FragColor。多的先不說,下面看一個小例子。

var geom = new THREE.SphereGeometry(10, 30, 20);
var mate = new THREE.ShaderMaterial({
    vertexShader: `
    varying vec3 vNormal;
    void main() {
                //將attributes的normal通過varying賦值給了向量vNormal
        vNormal = normal;
                //projectionMatrix是投影變換矩陣 modelViewMatrix是相機座標系的變換矩陣 最後我們將y值乘以1.4得到了一個形如雞蛋的幾何體
        gl_Position = projectionMatrix * modelViewMatrix * vec4( position.x, position.y * 1.4, position.z, 1.0 );
    }
    `,
    fragmentShader: `
        //片元著色器同樣需要定義varying vec3 vNormal;
    varying vec3 vNormal;
    void main() {
                //vNormal是一個已經歸一化的三維向量
        float pr = (vNormal.x + 1.0) / 2.0; //pr紅色通道值範圍為0~1
        float pg = (vNormal.y + 1.0) / 2.0; //pg綠色通道值範圍為0~1
        float pb = (vNormal.z + 1.0) / 2.0; //pb藍色通道值範圍為0~1
        gl_FragColor=vec4(pr, pg, pb, 1.0); //最後設定頂點顏色,點與點之間會自動插值
    }
    `
})
var mesh = new THREE.Mesh(geom, mate);
scene.add(mesh)

這篇我們簡單的操作頂點著色器和片元著色器繪製了一個五彩的雞蛋,但是這還僅僅是一個靜態的著色器,下一篇我們讓著色器材質動起來。

轉載請註明地址:郭先生的部落格

 

相關文章