[譯] THREE.JS入門教程-2.着色器-上


譯序

Three.js是一個偉大的開源WebGL庫,WebGL允許JavaScript操作GPU,在瀏覽器端實現真正意義的3D。但是目前這項技術還處在發展階段,資料極為匱乏,愛好者學習基本要通過Demo源碼和Three.js本身的源碼來學習。

國外網站 aerotwist.com 有六篇較為簡單的入門教程,我嘗試着將其翻譯過來,與大家分享。

0.簡介

之前我已經給出了一篇《開始使用Three.js》。如果你還沒有讀過,你可能需要去讀一下,本文的基礎是在那一篇教程的基礎上完成的。

我想討論一下着色器。在Three.js幫助你免去了很多麻煩之前,原生WebGL就很優秀了。有的時候,你也許會想要完成一些特定的效果,或者想對呈現在你的屏幕上的東西鑽研得更深入一些,那么着色器一定會進入你的視野。如果你像我一樣,你也同樣希望實現一些比上一篇教程中的基礎更加有意思的東西。這篇教程中,我會講解Three.js的基礎,這些基礎實際上為我們做了很多枯燥的工作。

在開始之前我還要說,這篇教程會有相當多的篇幅在解釋着色器的代碼,之后會有一篇教程會在着色器代碼的基礎上前進一點,利用着色器去做點什么。這是因為着色器shaders第一眼看上去並不易懂,需要一些解釋。

1.兩種着色器

WebGL沒有固定的渲染管線,你無法直接使用一個黑盒子式的着色器(譯者注:上個世紀的顯卡基本都只支持固定渲染管線);WebGL提供的是可編程的管線,這種方式更強大但也更難理解和使用。長話短說,可編程渲染管線意味着編寫程序的人要自己負責獲取頂點並將它繪制在屏幕上了。着色器是渲染管線的一部分,有兩種着色器:

  1. 頂點着色器
  2. 片元着色器

你應當知道的是,這兩種着色器都完全運行在顯卡的GPU上,我們將需要它們處理的數據從CPU上卸下,裝到GPU上,減輕了CPU的復旦。現代的GPU對着色器需要的調用的運算類型都做了大幅優化,這樣做很值得。

2.頂點着色器

基元形狀,比如一個球體,是由頂點構成的,是吧?頂點着色器被依次傳入這些頂點中的一個頂點,然后處理它。如何處理每個頂點是可以自由定制的,但頂點着色器有一個必做的事,就是為一個名為 gl_Position 的變量賦值,該變量是一個4維數組,表示該頂點最終在屏幕上的位置。這本身是個有意思的過程,因為我們實際上在談論如何將一個三維坐標(一個具有x、y、z值得頂點)轉化為,或者說投影到二維的屏幕上。謝天謝地,要是我們使用Three.js之類的工具,我們能夠如此方便地訪問到 gl_Position

3.片元着色器

現在我們有包含頂點的三維物體了,現在要將物體投影到二維屏幕上了,但顏色哪里去了?紋理和光照呢?這正是片元着色器要處理的。

和頂點着色器類似,片元着色器有一項必須完成的任務:設置或消除變量 gl_FragColor ,另一個四維浮點變量,也就是片元點最終的顏色。什么是片元?想象一個具有三個頂點的三角形,片元就是經過這三個頂點計算后的,所有在三角形內部的點。因此,片元值由頂點的值內插生成。如果一個頂點的顏色是紅色,相鄰頂點的顏色是藍色,那么我們可以觀測到顏色從紅色頂點附近漸變,由紅色變成紫色,最終在藍色頂點附近變成藍色。

4.着色器變量

說到着色器變量,有三種:UniformaAttributesVaryings。當我第一次聽到這三個詞語時,我很困惑,因為它們和我之前用到的東西完全不匹配。但現在,你可以這樣理解它們:

  1. Uniforms變量既可以傳入頂點着色器,也可以傳入片元着色器,它們包含了哪些在整個渲染過程中保持不變的變量,比如,一個點光源的位置。
  2. Attributes變量對應於每個頂點,它們只可以傳入頂點着色器中,比如每個頂點都具有一個顏色。Attributes變量和頂點的關系是一一對應的。
  3. Varyings變量是在頂點着色器中定義,並且准備傳入給片元着色器的變量。為了確保這點,我們需要確保在兩個着色器中變量的類型和命名完全一致。一個經典的應用是法線向量,因為在計算光照的時候需要用到法線。

在后面一篇教程中,我會使用這三種變量,你也會學習到這三種變量如何真正應用起來得。

現在,我們已經談過了頂點着色器、片元着色器和三種着色器變量。是時候來看一個我們可以創建的最簡單的着色器了。

5.Hello World(譯者吐槽:能不能不要秀法語啊)

這兒有一個最簡單的頂點着色器: 

/**
 * 每個頂點坐標乘以模型視圖矩陣在乘以投影矩陣
 * 獲得在二維屏幕上的坐標
 */
void main() {
  gl_Position = projectionMatrix *
                modelViewMatrix *
                vec4(position,1.0);
}

一個最簡單的片元着色器:

/**
 * 將任意一個像元色設置為粉紅
 */
void main() {
  gl_FragColor = vec4(1.0,  // R
                      0.0,  // G
                      1.0,  // B
                      1.0); // A
}

這就是全部了。如果現在直接運行的話,你就可以在屏幕上看到一個“無光”的粉紅色形體。不是很復雜,是嗎?

在頂點着色器中,我們通過Three.js傳入了一些uniforms變量。有兩個4×4的矩陣uniforms變量:模型視圖矩陣和投影矩陣。你並不需要太了解這兩個矩陣是怎么工作的。簡單地說,這兩個矩陣描述了三維點坐標如何投影成為二維屏幕上的坐標。

事實上,我只介紹了這兩段簡短的代碼段。Three.js在你自己的着色器代碼前已經將它們加進來了,所以你不必擔心。實話說,Three.js還加了很多東西在你的代碼前面,比如光照數據、節點顏色和節點法向量等等。如果沒有Three.js你要親自創建並設置這些對象,真的。

6.使用着色器材質

/**
 * 假設我們可以使用JQuery
 * 將着色器的代碼文本從DOM中抽取出來
 */
var vShader = $('vertexshader');
var fShader = $('fragmentshader');
var shaderMaterial =
  new THREE.ShaderMaterial({
    vertexShader:   vShader.text(),
    fragmentShader: fShader.text()
  }); 

看看效果

從這兒開始,Three.js將會編譯並運行你的着色器,將其連接在你創建的材質上,材質又依附於你創建的mesh上。它並沒有變得比真的更容易。也許是這樣吧,但我們在考慮瀏覽器3D編程,我想你應該預期,這個話題是有一定復雜性的。

我們還可以像着色器材質添加另外兩種屬性:uniforms和attributes。他們可以是向量、整數或者浮點數,但是如我之前所說,uniforms變量在計算所有點的過程中保持不變,所以它們更加可能是單一的值,而attributes變量是對每個頂點而言的,所以他們應當是數組。在一個mesh中,attribute變量和頂點應當是一一對應的。

7.小結

這篇教程就到這里了,實際上我已經講得很多了,但是在許多方面我都只是一掠而過。在下一篇教程中我會提供一個復雜的着色器,通過它我將傳入一些attributes變量和uniforms變量來做一些模擬光照效果。

我將這篇教程的源碼打包了,你可以下載下來作為參考。如果你喜歡,可以通過emailTwitter聯系我。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM