WebGL是什么?

改革開發(fā)40年以來,世界日新月異,無論從生活到精神上都有了顛覆性的變化,曾經(jīng)教授還是教書的,磚家還叫專家,太陽還不叫日,菊花還是一種花,老王還沒那么多,Web還只需要做IE,XHR還沒出生的時(shí)候,怎么能想到現(xiàn)在瀏覽器會提供如此豐富多彩的多媒體生活,無論是音頻、視頻、以及各種漂亮的頁面都在讓用戶更好的擁抱著互聯(lián)網(wǎng),當(dāng)二維頁面無法滿足用戶之后,會出現(xiàn)什么樣的內(nèi)容來繼續(xù)推進(jìn)Web進(jìn)展呢,沒錯,就是3D,瀏覽器中看到的內(nèi)容從平面變成3D的時(shí)候,oH,My God,提起來都讓人興奮。

網(wǎng)站的未來是這樣子的:

未來效果

的確,3D技術(shù)會讓平淡的網(wǎng)頁變的更酷,更讓人眼花撩眼,這本后隱藏著什么呢?來來,咱們做下來泡一壺茶,邊喝邊聊,這個神奇的家伙叫做WebGL

談起WebGL可能有一些人比較陌生,實(shí)際上WebGL是一種3D繪圖標(biāo)準(zhǔn),這種繪圖技術(shù)標(biāo)準(zhǔn)允許把JavaScript和OpenGL ES 2.0結(jié)合在一起,通過增加OpenGL ES 2.0的一個JavaScript綁定,WebGL可以為HTML5 Canvas提供硬件3D加速渲染,這樣Web開發(fā)人員就可以借助系統(tǒng)顯卡來在瀏覽器里更流暢地展示3D場景和模型了,還能創(chuàng)建復(fù)雜的導(dǎo)航和數(shù)據(jù)視覺化。顯然,WebGL技術(shù)標(biāo)準(zhǔn)免去了開發(fā)網(wǎng)頁專用渲染插件的麻煩,可被用于創(chuàng)建具有復(fù)雜3D結(jié)構(gòu)的網(wǎng)站頁面,甚至可以用來設(shè)計(jì)3D網(wǎng)頁游戲等等。

此鏈接可以查看你的游覽器是否支持WebGL以及支持的版本。
檢測瀏覽器是否支持WebGL

看WebGL的背景實(shí)際上是JavaScript操作一些OpenGL接口,也就意味著,可能會編寫一部分GLSL ES 2.0的代碼,沒錯,你猜對了,WebGL只是綁定了一層,內(nèi)部的一些核心內(nèi)容,如著色器,材質(zhì),燈光等都是需要借助GLSL ES語法來操作的.

基于WebGL周邊也衍生了眾多的第三方庫,如開發(fā)應(yīng)用類的Three.js,開發(fā)游戲類的Egert.js等,都大大的降低了學(xué)習(xí)WebGL的成本,但是本著有問題解決問題,沒問題制造問題在解決問題的程序猿態(tài)度,還是覺得應(yīng)該稍微了解一下WebGL一些基本的概念,以便能更好的去理解不同框架帶來的便捷以及優(yōu)勢。

接下來先簡單介紹一下使用到的知識要點(diǎn)。

創(chuàng)建webGL對象

不同瀏覽器生命WebGL對象方式有所區(qū)別,雖然大部分瀏覽器都支持experimental-webgl,而且以后會變成webgl,所以創(chuàng)建時(shí)做一下兼容處理

var canvas = document.getElementById("glcanvas");
gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");

著色器

WebGL依賴一種新的稱為著色器(shader)的繪圖機(jī)制。著色器提供了靈活且強(qiáng)大的繪制二維或三維圖形的方法,所有WebGL必須使用它。著色器不僅強(qiáng)大,而且更復(fù)雜,僅僅通過一條簡單的繪圖指令是不能操作它的。

WebGL需要兩種著色器

  • 頂點(diǎn)著色器(Vertex shader):頂點(diǎn)著色器是用來描述頂點(diǎn)特性(如位置、顏色等)的程序。頂點(diǎn)(Vertex)是指二維或三維空間的一個點(diǎn),比如二維或三維空間線與線之間的交叉點(diǎn)或者端點(diǎn)。
  • 片元著色器(Fragment shader):進(jìn)行逐片元處理過程(如光照等)的程序。片元(fragment)是一個WebGL的術(shù)語,你可以將其理解成像素。

著色器語言使用的是GLSL ES語言,所以在javascript需要將之存放在字符串中,等待調(diào)用編譯

創(chuàng)建頂點(diǎn)著色器:

var VSHADER_SOURCE = 
  'void main() {\n' +
    '  gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n' +
    '  gl_PointSize = 10.0;\n' + 
  '}\n';

創(chuàng)建片元著色器:

 var FSHADER_SOURCE =
    'void main() {\n' +
    '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
'}\n';

瀏覽器的整個過程如下:


webgl渲染過程

著色器中包含幾個內(nèi)置變量:gl_Position, gl_PointSize, gl_FragColor。

著色器語言中涉及到vec4的數(shù)據(jù)類型,此數(shù)據(jù)類型是一個思維浮點(diǎn)數(shù)組,所以其值不可以是整形如(1,1,1,1),正確應(yīng)為:(1.0,1.0,1.0,1.0)

  • gl_Position: 為一種vec4類型的變量,且必須被賦值。四維坐標(biāo)矢量,我們稱之為齊次坐標(biāo),即(x,y,z,w)等價(jià)于三維左邊(x/w,y/w,z/w),w相當(dāng)于深度,沒有特殊要求設(shè)置為1.0即可。
  • gl_PointSize:表示頂點(diǎn)的尺寸,也是浮點(diǎn)數(shù),為非必填項(xiàng),如果不填則默認(rèn)顯示為1.0。
  • gl_FragColor:該變量為片元著色器唯一的內(nèi)置變量,表示其顏色,也是一個vec4類型變量,分別代表(R,G,B,A),不過顏色范圍是從0.0-1.0對應(yīng)Javascript中的#00-#FF
    有了著色器我們就可以著手去繪制圖像了,既然繪制3D圖形,必然會有對應(yīng)的三維坐標(biāo)系,WebGL采用右手坐標(biāo)系,如圖所示:
右手坐標(biāo)系

使用著色器

讓我們來看看如何把著色器代碼編譯并且使用起來

著色器代碼需要載入到一個程序中,webgl使用此程序才能調(diào)用著色器。

var program = gl.createProgram();
// 創(chuàng)建頂點(diǎn)著色器 
var vShader = gl.createShader(gl.VERTEX_SHADER);
// 創(chuàng)建片元著色器 
var fShader = gl.createShader(gl.FRAGMENT_SHADER);
// shader容器與著色器綁定 
gl.shaderSource(vShader, VSHADER_SOURCE);
gl.shaderSource(fShader, FSHADER_SOURCE);
// 將GLSE語言編譯成瀏覽器可用代碼 
gl.compileShader(vShader);
gl.compileShader(fShader);
// 將著色器添加到程序上 
gl.attachShader(program, vShader);
gl.attachShader(program, fShader);
// 鏈接程序,在鏈接操作執(zhí)行以后,可以任意修改shader的源代碼,
對shader重新編譯不會影響整個程序,除非重新鏈接程序 
gl.linkProgram(program);
// 加載并使用鏈接好的程序 
gl.useProgram(program);

讓我們嘗試?yán)L制一個點(diǎn)

gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS, 0 ,1);

我們來看一看最終結(jié)果,果然出來了一個點(diǎn)

一個點(diǎn)效果圖

,

Why? 咋這么模糊?沒錯不是你的眼鏡度數(shù)又高了,的確是模糊的。

讓我們來說說WebGL的坐標(biāo)系

因?yàn)閃ebGL的坐標(biāo)系與實(shí)際頁面中的坐標(biāo)系是不同的,如下圖,普通canvas坐標(biāo)系與正常的瀏覽器像素值相同,但WebGL中的坐標(biāo)系是以整個WebGL中心點(diǎn)為(0.0,0.0),而且坐標(biāo)的精確度為小數(shù)點(diǎn)后一位。坐標(biāo)系對比如下圖所示:

坐標(biāo)系對比

圖上的實(shí)例是在使用源生WebGL時(shí),并且未對視角有設(shè)置的情況下的默認(rèn)值。默認(rèn)視角的位置為(0.0, 0.0, 0.0),并且lookAt(0.0, 0.0, -1.0),也就是默認(rèn)的視角是看向z軸負(fù)坐標(biāo)的,如果點(diǎn)在z的正位置上,則是無法看到點(diǎn)的。

繪制之后,發(fā)現(xiàn)這個依舊會繪制出超級模糊的圖像,那是因?yàn)檎麄€WebGL的尺寸是與canvas寬度與高度相關(guān)連的,并且canvas的寬度與高度如果用css來設(shè)置的話,會被默認(rèn)成100×100,也就意味著,你繪制出來的圖形是把100×100的圖形拉伸到當(dāng)前canvas的尺寸中。所以正確的設(shè)置canvas的方式應(yīng)該如下:

//錯誤
<canvas id="glcanvas" style="width: 700px; height: 500px;">
//正確的方式
<canvas id="glcanvas" width="700" height="500">

一個真實(shí)尺寸的清晰的點(diǎn)就出現(xiàn)了


清晰點(diǎn)繪制成功

但我們辛苦繪制出來的點(diǎn)居然是正方形的,但WebGL是未提供繪制圓點(diǎn)的方法。

我們首先來了解一下WebGL的渲染機(jī)制,頂點(diǎn)著色器的信息在傳遞給OpenGL底層繪制的時(shí)候,會先進(jìn)行光柵化,也就是把點(diǎn)轉(zhuǎn)化成對應(yīng)的像素。然后在片元著色器會逐個點(diǎn)進(jìn)行渲染,最終就達(dá)到了視覺看到的效果。

光柵化

點(diǎn)也是一樣,會將點(diǎn)轉(zhuǎn)變成多個像素點(diǎn),所以要變成圓點(diǎn),需要如下的方式:


繪制圓點(diǎn)方式

我們需要在片元著色器中來處理,將非原型區(qū)域的像素點(diǎn),不用片元著色器來繪制,著色器需要判斷距離圓點(diǎn)的位置超過0.5的話,就忽略此片元點(diǎn),最終就會出現(xiàn)一個圓點(diǎn)的效果。

var FSHADER_SOURCE = `
 #ifdef GL_ES
     precision mediump float;
 #endif
void main() {
  float d = distance(gl_PointCoord, vec2(0.5,0.5));
    if(d < 0.5){
      gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }else{ discard;} 
}`;

如下圖,我們繪制了一個圓點(diǎn):


圓點(diǎn)

本章我們已經(jīng)了解了WebGL的一些背景,以及如何使用一些基本功能,那么如何把著色器動態(tài)化并且同時(shí)高性能的繪制大量點(diǎn)呢?下一章我們會解開WebGL緩存區(qū)的面紗。

擴(kuò)展閱讀

[1] http://webglreport.com

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容