Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Web Development
Code

WebGL基礎教程:第一部分

by
Length:LongLanguages:
This post is part of a series called WebGL Essentials.
WebGL Essentials: Part II

Chinese (Traditional) (中文(繁體)) translation by Stypstive (you can also view the original English article)

WebGL是一種基於OpenGL的瀏覽器內置3D渲染器,它可以讓你在HTML5頁面中直接顯示3維內容。 在本教程中,我會介紹你使用此框架所需的所有基礎內容。


介紹

開始學習之前,有幾件事你是需要了解的。 WebGL是將3D內容渲染到HTML5的canvas元素上的一種JavaScript API。 它是利用"3D世界"中稱為著色器的兩種腳本來實現這一點的。 這兩種著色器分別是:

  • 頂點著色器
  • 片元著色器

聽到這些名詞時也不要過於驚慌;它們只不過是"位置計算器"和"顏色選擇器"的另一種說法罷了。 片元著色器容易理解;它只是告訴WebGL,模型上的指點定應該是什麼顏色。 而頂點著色器解釋起來就需要點技術了,不過基本上它起到將3維模型轉變為2維坐標的作用。 因為所有的計算機顯示器都是2維平面,當你在屏幕上看3維物體時,它們只不過是透視後的幻象。

如果你想完整地理解這個計算過程,你最好是問一個數學家,因為這個過程中用到了高級的4x4矩陣乘法,實在是有點超過我們這個"基礎"教程的範圍呀。 幸運的是,你並不需要知道它所有的工作原理,因為WebGL會處理背後大部分的細節。 那麼,我們開始吧。


第一步:設置WebGL

WebGL有許多細微的設置,而且每次你​​要在屏幕畫什麼東西之前都要設置一遍。 為了節約時間,並使代碼整潔一些,我們把所有"幕後"的代碼包裝成一個JavaScript對象,並存於一個獨立的文件中。 現在我們要開始了,先創建一個新文件'WebGL.js',並寫入如下代碼:

這個構造函數的參數是canvas無形的ID,以及兩個著色器對象。 首先,我們要獲得canvas元素,並確保它是支持WebGL的。 如果支持WebGL,我們就將WebGL上下文賦值給一個局部變量,稱為"GL"。 清除顏色(clearColor)其實就是設置背景顏色,值得一提的是,WebGL中大部分參數的取值範圍都是0.0到1.0,所以我們需要讓通常的rgb值除以255。 所以,我們的示例中,1.0,1.0,1.0,1.0表示背景為白色,且100%可見 (即無透明)。 接下來兩行要求WebGL計算深度和透視,這樣離你近的對象會擋住離你遠的對象。 最後,我們設置寬高比,即canvas的寬度除以它的高度。

繼續前行之前,我們要準備好兩個著色器。 我把這些著色器寫到HTML文件裡去,這個HTML文件裡還包含了我們的畫布元素 (canvas)。 創建一個HTML文件,並將下面的兩個script元素放在body標籤之前。

先來看頂點著色器,我們定義了兩個屬性 (attributes):

  • 頂點位置,它存儲了當前頂點 (你的模型上的點) 的位置,包括x,y,z坐標。
  • 紋理坐標,即賦給這個點的紋理在紋理圖像中的位置

接下來,我們創建變換和透視矩陣等變量。 它們被用於將3D模型轉化為2D圖像。 下一行是創建一個與片元著色器共享的變量vTextureCoord,在主函數中,我們計算gl_Position (即最終的2D位置)。 然後,我們將'當前紋理坐標'賦給這個共享變量vTextureCoord。

在片元著色器中,我們取出定義在頂點著色器中的這個坐標,然後用這個坐標來對紋理進行'採樣'。 基本上,通過這個過程,我們得到了我們幾何體上的當前點處的紋理的顏色。

現在寫完了著色器,我們可回過頭去在JS文件中加載這些著色器。 將"//Load Shaders Here"換成如下代碼:

你的紋理必須是偶數字節大小,否則會出錯...比如2x2,4x4,16x16,32x32...

首先,我們要確保這些著色器是存在的,然後,我們逐一地加載它們。 這個過程基本上是:得到著色器源碼,編譯,附著到核心的著色程序上。 從HTML文件中提取著色器源碼的代碼,封裝到了一個函數中,稱為LoadShader;稍後會講到。 我們使用這個'著色器程序'將兩個著色器鏈接起來,通過它,我們可以訪問到著色器中的變量。 我們將數據儲存到定義在著色器中的屬性;然後,我們就可以將幾何體輸入到著色器中了。

現在,讓我們看一下LoadShader函數,你應該將它置於WebGL函數之外。

基本上,這個函數通過遍歷著色器來收集源碼。


第二步:“簡單”立方體

為了在WebGL中畫出對象,你需要如下三個數組:

  • 頂點 (vertices):構造你的對象的那些點
  • 三角形 (triangles):告訴WebGL如何將頂點連接成面
  • 紋理坐標 (texture coordinates):定義頂點如何被映射到紋理圖像上

這個過程稱為UV映射。 我們的例子是構造一個簡單的立方體。 我將這個立方體分成4個頂點一組,每一組又連成兩個三角形。 我們可以用一個變量來存儲立方體的這些數組。

這樣一個簡單的立方體用到的數據似乎有點過多,不過,在我們教程的第二部分中,我們寫一個導入3D模型的腳本,所以你現在不必計較這些。

你可能還在想,為什麼需要24個頂點 (每一面4個) 呢,實際上只有8個呀? 我這樣做是因為,你可以只用為每個頂點指定一個紋理坐標;而如果你用8個頂點,則整個立方體將看起來一樣,因為它會將一個紋理值傳播到頂點接觸的所有面上。 通過我們的方式,每個面都有它獨有的點,所以我們可以在每一面上指定不同的紋理區域。

現在,我們有了這樣一個立方體變量 cube,然後,我們可以準備畫它了。 我們還是回到WebGL方法中,並添加一個Draw函數。


第三步:Draw函數

WebGL中繪製對象的過程有許多步驟;所以最好是將每個步驟寫成函數,來簡化這個過程的代碼。 基本的想法是將三個數組加載到WebGL的緩存中去。 然後,我們將這些緩存連接到著色器中定義的屬性,以及變換和透視矩陣。 接下來,我們需要將紋理加載到內存中,並且最後調用draw命令。 那麼,我們開始吧。

接下來的代碼進入到WebGL函數中:

頂點著色器對你的對象進行放置,旋轉和縮放時,依據的都是變換和透視矩陣。 在本教程第二部分中,我們會更深入地介紹變換。

我已經添加了兩個函數:MakePerspective()MakeTransform()。 它們只不過生成了WebGL所需的4x4矩陣。 MakePerspective()函數接受幾個參數:視場豎直高度,寬高比,最近和最遠點。 任何比1個單位近或比10000個單位遠的對像都不會被顯示,但是你可以調整這些值,以得到你所期望的效果。 現在,讓我們看一看這兩個函數:

這些矩陣都會影響到你的對象的最終視覺效果,但透視矩陣影響的是你的“3維世界”,比如視場和可見對象,而變換矩陣影響的是單個對象,比如它們的旋轉和位置。 完成這些之後,我們幾何可以開始畫了,剩下的工作只是將一個圖像轉變為一個WebGL紋理。


第四步:加載紋理

加載一個紋理分兩步。 首先,我們要用JavaScript的標準做法來加載一幅圖像,然後,我們將其轉化為一個WebGL紋理。 所以,我們先從第二步開始吧,畢竟我們正在討論的是JS文件。 將下面的代碼加到WebGL函數的底部,恰好在Draw命令之後。

值得一提的是,你的紋理大小必須是偶數字節,否則你會得到錯誤信息;比如它們可能的維度包括:2x2,4x4,16x16,32x32,等等。 我另加了一行來翻轉Y坐標,只是因為我的3D應用的Y坐標是朝後的,但是否這樣做完全取決於你。 這是因為一些程序取Y的零點為左上角,而其它則為左下角。 我設置的這些縮放性質只是告訴WebGL,圖像應該如何向上採樣和向下採樣。 你可以使用其它的選項來得到不同的效果,不過我認為這個組合效果最佳。

現在,我們完成了JS文件,我們可以回到HTML文件,來完成最後一步了。


第五步:合起來

如前所述,WebGL是在canvas元素上畫畫。 因此,在body部分裡,我們所需要的就只是一個canvas畫布。 在添加canvas元素之後,你的html頁面看起來像下面這樣:

這個頁面相當簡單。 在head區域,我鏈接了JS文件。 現在,讓我們實現Ready函數,它在頁面加載時調用。

所以,我們創建一個新的WebGL對象,並將canvas和著色器的ID傳遞進去。 接下來,我們加載紋理圖像。 一旦加載完成,我們對立方體Cube和紋理Texture調用Draw()方法。 如果你一路跟下來,你的屏幕上應該有一個覆蓋有紋理的靜止立方體。

雖然我說了下一次再講變換,但我們不可能只丟給你一個靜止矩形,這還不夠三維。 讓我們回過頭去,再添加一個小小的旋轉吧。 在HTML文件中,修改onload函數,使之如下面的代碼:

這會使得每隔33毫秒調用一個稱為Update()的函數,因而我們得到約30fps的幀率。 下面是這個更新函數:

這個函數相當簡單;它只不過清除屏幕,然後繪製更新後的立方體。 現在,讓我們進入JS文件,添加旋轉代碼。


第六步:添加一些旋轉

我們不會完全實現變換的代碼,因為我說了要等到下次現說,這次我們只是加一個繞Y軸的旋轉。 要做的第一件事就是在Cube對像中加一個Rotation變量。 它會跟踪當前的角度,並讓我們可以遞增地保持旋轉。 所以你的Cube變量的頂部代碼應該如下面這樣:

現在,讓我們修改MakeTransform()函數,添加旋轉功能:


結論

搞定! 在下一個教程中,我們會介紹加載模型和執行變換。 我希望你喜歡這個教程;歡迎在後面提出任何問題或留言。

Envato qr branded
关注我们的公众号
Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.