說起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)
這篇我們簡單的操作頂點着色器和片元着色器繪制了一個五彩的雞蛋,但是這還僅僅是一個靜態的着色器,下一篇我們讓着色器材質動起來。
轉載請注明地址:郭先生的博客