摘要:中有兩種著色器定點(diǎn)著色器和片段或像素著色器。頂點(diǎn)著色器用于將頂點(diǎn)轉(zhuǎn)換為需要渲染的點(diǎn)。的著色器是使用,著色器寫的,是一種與和完全不同的語言。為著色器傳遞數(shù)據(jù)的方式有兩種和。通過可以向頂點(diǎn)著色器傳入頂點(diǎn)信息,通過可以向任何著色器傳入常量值。
OpenGl:www.opengl.org
WebGL:www.learningwebgl.com
WebGL是針對Canvas的3D上下文;OpenGL等是3D圖形語言;
類型化數(shù)組類型化數(shù)組也是數(shù)組,只不過其元素被設(shè)置為特定類型的值。
數(shù)組緩沖器ArrayBuffer類型和byteLength屬性類型化數(shù)組的核心就是一個名為
ArrayBuffer的類型。每個ArrayBuffer對象表示的只是內(nèi)存中指定的字節(jié)數(shù),但不會指定這些字節(jié)用于保存什么類型的數(shù)據(jù)。通過ArrayBuffer能做的,就是為了將來使用而分配一定數(shù)量的字節(jié)。
如:
var buffer = new ArrayBuffer(20); //在內(nèi)存中分配20B
屬性
byteLength 返回它包含的字節(jié)數(shù)
如:
var buffer = new ArrayBuffer(20); console.log(buffer.byteLength); //20數(shù)組緩沖器視圖 DataView數(shù)組緩沖器視圖
使用ArrayBuffer(數(shù)組緩沖器類型)的一種特別的方式就是用它來創(chuàng)建數(shù)組緩沖器視圖。其中,最常見的視圖是
DataView,通過它可以選擇ArrayBuffer中的一小段字節(jié)。為此,可在創(chuàng)建DataView實(shí)例的時候傳入一個ArrayBuffer、一個可選的字節(jié)偏移量(從該字節(jié)開始選擇)和一個可選的要選擇的字節(jié)數(shù)。
如:
var view = new DataView(buffer); //新的視圖 var view = new DataView(buffer, 6); //開始于字節(jié)6的新視圖 var view = new DataView(buffer, 6, 9); //開始于字節(jié)6,結(jié)束于字節(jié)9的新視圖DataView的屬性byteOffset和byteLength
DataView對象會把字節(jié)偏移量以及字符長度信息保存在
byteOffset
byteLength
兩個屬性中:
var view = new DataView(buffer, 6, 9); //開始于字節(jié)6,結(jié)束于字節(jié)9的新視圖 console.log(view.byteOffset); //6 字節(jié)偏移量為6 console.log(view.byteLength); //9 字節(jié)長度為9
buffer屬性也可以取得數(shù)組緩沖器;
getter和setter讀寫方法讀取和寫入DataView的時候,要根據(jù)實(shí)際操作的數(shù)據(jù)類型,選擇相應(yīng)的
getter
setter
如下,列出了DataView支持的數(shù)據(jù)類型以及相應(yīng)的讀寫方法:
getter:
getInt8(byteOffset) 方法: 在相對于視圖開始處的指定字節(jié)偏移量位置處獲取 Int8 值。
getUint8(byteOffset) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處獲取 Uint8 值。
getInt16(byteOffset,littleEndian) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處獲取 Int16 值。
getUint16(byteOffset,littleEndian) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處獲取 Uint16 值。
getInt32(byteOffset,littleEndian) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處獲取 Int32 值。
getUint32(byteOffset,littleEndian) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處獲取 Uint32 值。
getFloat32(byteOffset,littleEndian) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處獲取 Float32 值。
getFloat64(byteOffset,littleEndian) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處獲取 Float64 值。
setter:
setInt8(byteOffset,value) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處存儲 Int8 值。
setUint8(byteOffset,value) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處存儲 Uint8 值。
setInt16(byteOffset,value,littleEndian) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處存儲 Int16 值。
setUint16(byteOffset,value,littleEndian) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處存儲 Uint16 值。
setInt32(byteOffset,value,littleEndian) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處存儲 Int32 值。
setUint32(byteOffset,value,littleEndian) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處存儲 Uint32 值。
setFloat32(byteOffset,value,littleEndian) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處存儲 Float32 值。
setFloat64(byteOffset,value,littleEndian) 方法 (DataView): 在相對于視圖開始處的指定字節(jié)偏移量位置處存儲 Float64 值。
如:
var buffer = new ArrayBuffer(20); var view = new DataView(buffer); view.setUint16(0,25); //0000000000001001 var value = view.getUint8(0); //00000000 console.log(value); //0
類型化視圖在讀寫數(shù)組緩沖器中更加便利:
類型化視圖(類型化數(shù)組)類型化視圖一般也被稱為類型化數(shù)組,因?yàn)樗鼈兂嗽乇仨毷悄撤N特定的數(shù)據(jù)類型外,與常規(guī)的數(shù)組無異。類型化視圖也分幾種,而且它們都繼承了DataView。
Int8Array:表示8為二補(bǔ)整數(shù)。
Uint8Array:表示8位無符號整數(shù)。
Int16Array:表示16位二補(bǔ)整數(shù)。
Uint16Array:表示16位無符號整數(shù)。
Int32Array:表示32為二補(bǔ)整數(shù)。
Uint32Array:表示32位無符號整數(shù)。
Float32Array:表示32位IEEE浮點(diǎn)值。
Float64Array:表示64位IEEE浮點(diǎn)值。
需要三個參數(shù),只有第一個是必須的:ArrayBuffer對象、字節(jié)偏移量、要包含的字節(jié)數(shù),如:
var buffer = new ArrayBuffer(20); var int8s = new Int8Array(buffer);
注意:20B的ArrayBuffer可以保存20個Int8Array或Uint8Array,或者10個Int16Array或Uint16Array,或者5個Int32Array或Uint32Array或Float32Array,或者2個Float64Array。
var buffer = new ArrayBuffer(20); var int8s = new Int8Array(buffer); //創(chuàng)建一個新數(shù)組,使用整個緩沖器 var int16s = new Int16Array(buffer, 9); //只使用從字節(jié)9開始的緩沖器 var uint16s = new Uint16Array(buffer, 9, 10); //只使用從字節(jié)9到字節(jié)10的緩沖器
能夠指定緩沖器中可用的字節(jié)段,意味著能在同一個緩沖器中保存不同類型的數(shù)值,如下面的代碼就是在緩沖器的開頭保存8位整數(shù),而在其他字節(jié)中保存16位整數(shù):
var buffer = new ArrayBuffer(30); //緩沖器中有30個字節(jié) var int8s = new Int8Array(buffer, 0, 10); //前面10個字節(jié)存儲10個8位整數(shù) var int16s = new Int16Array(buffer, 10, 10); //后面還有20個字節(jié),2個字節(jié)存儲1個16位整數(shù),所以只能存儲10個
另外,每個視圖構(gòu)造函數(shù)都有一個名為
BYTES_PER_ELEMENT
表示類型化數(shù)組的每個元素需要多少字節(jié):
console.log(Float64Array.BYTES_PER_ELEMENT) //8
這樣就可以利用這個屬性來輔助初始化:
var buffer = new ArrayBuffer(20); var int8s = new Int8Array(buffer, 0, 10 * Int8Array.BYTES_PER_ELEMENT); var int16s = new Int16Array(buffer, int8s.byteOffset + int8s.byteLength, (10 / Int16Array.BYTES_PER_ELEMENT));
另外,還可以不用首先創(chuàng)建ArrayBuffer對象,只要傳入希望數(shù)組保存的元素數(shù),相應(yīng)的構(gòu)造函數(shù)就可以自動創(chuàng)建一個包含足夠字節(jié)數(shù)的ArrayBuffer對象:
var int16s = new Int16Array(10); //創(chuàng)建一個數(shù)組保存10個16位整數(shù)(10字節(jié)) var int32s = new Int32Array(1); //創(chuàng)建一個數(shù)組保存1個32位整數(shù)(4字節(jié))
另外還可以把常規(guī)數(shù)組轉(zhuǎn)換為類型化視圖:
var int8s = new Int8Array([1,2,3,4]); var view = new DataView(int8s.buffer); console.log(int8s.toString()); //1234 console.log(view.byteLength); //4
對類型化視圖的迭代:
for (var i = 0; i < int8s.length; i++) { console.log(int8s[i]); };
也可以使用方括號語法為類型化視圖的元素賦值:
var uint16s = new Uint16Array(10); uint16s[0] = 65537; console.log(uint16s[0]); //1
另外可以通過
subarray()方法基于底層數(shù)組緩沖器的子集創(chuàng)建一個新視圖,接收兩個參數(shù):開始元素的索引,可選的結(jié)束元素的索引:
如:
var uint16s = new Uint16Array(10), sub = uint16s.subarray(2, 5);WebGL上下文
目前,在支持的瀏覽器中,WebGL的名字叫做“experimental-webgl”,這是因?yàn)閃ebGL規(guī)范仍然未制定完成。制定完成后,這個上下文的名字就會變成簡單的“webgl”。如果瀏覽器不支持WebGL,那么取得該上下文時會返回null。
var drawing = document.getElementById("drawing"); if (drawing.getContext) { var gl = drawing.getContext("experimental-webgl"); if (gl) { //[...] } }
通過給getContext()傳遞第二個參數(shù),可以為WebGL上下文設(shè)置一些選項(xiàng)。這個參數(shù)本身是一個對象,可以包含下列屬性:
* `alpha`:值為true,表示為上下文創(chuàng)建一個Alpha通道緩沖區(qū);默認(rèn)值為true; * `depth`:值為true,表示可以使用16位深緩沖區(qū);默認(rèn)值為true; * `stencil`:值為true,表示可以使用8位模板緩沖區(qū);默認(rèn)值為false; * `antialias`:值為true,表示將使用默認(rèn)機(jī)制執(zhí)行抗鋸齒操作;默認(rèn)值為true。 * `premultipliedAlpha`:值為true,表示繪圖緩沖區(qū)有預(yù)乘Alpha值;默認(rèn)為true; * `preserveDrawingBuffer`:值為true;表示在繪圖完成后保留繪圖緩沖區(qū);默認(rèn)值為false。
傳遞這個選項(xiàng)對象的方式如下:
var drawing = document.getElementById("drawing"); if (drawing.getContext) { var gl = drawing.getContext("experimental-webgl", { alpha: false }); if (gl) { //[...] } }
大多數(shù)情況下不用開啟,因?yàn)榭赡苡绊懙叫阅?,而且默認(rèn)值一般都能滿足我們需求。
如果getContext()無法創(chuàng)建WebGL上下文,瀏覽器可能會報錯。所以應(yīng)該把它封裝到try-catch塊中:
var drawing = document.getElementById("drawing"); if (drawing.getContext) { try { var gl = drawing.getContext("experimental-webgl"); } catch (e) {} if (gl) { //[...] } }常量
在WebGL中,保存在上下文對象中的這些常量都沒有GL_前綴。
方法命名方法名的后綴會包含參數(shù)個數(shù)(1到4),和接收的數(shù)據(jù)類型(f為浮點(diǎn)數(shù),i為整數(shù)),如:gl.uniform4f()意味著要接收4個浮點(diǎn)數(shù);另外還有很多方法接收數(shù)組參數(shù)而非一個個多帶帶的參數(shù),這樣的方法中名字包含字母v,如:gl.uniform3iv()可以接收一個包含3個值的整數(shù)數(shù)組。
準(zhǔn)備繪圖在實(shí)際操作WebGL上下文之前,一般都要使用某種實(shí)色清除canvas元素,為繪圖做好準(zhǔn)備。為此,首先必須使用:
clearColor()方法來指定要使用的顏色值,這個方法接收4個參數(shù):紅、綠、藍(lán)和透明度。每個參數(shù)必須是一個0到1之間的數(shù)值,表示每種分量在最終顏色中的強(qiáng)度。
如:
var drawing = document.getElementById("drawing"); if (drawing.getContext) { try { var gl = drawing.getContext("experimental-webgl"); } catch (e) {} if (gl) { gl.clearColor(0,0,0,1); //把清理緩沖區(qū)的值設(shè)置為黑色 gl.clear(gl.COLOR_BUFFER_BIT); //調(diào)用clear方法,傳入?yún)?shù)gl.COLOR_BUFFER_BIT告訴WebGL使用之前定義的顏色來填充相應(yīng)區(qū)域。 } }視口與坐標(biāo)
開始繪圖之前,通常要先定義WebGL的視口(viewport)。默認(rèn)情況下,視口可以使用整個canavs區(qū)域。要改變視口大小,可以調(diào)用
viewport()方法并傳入4個參數(shù):(視口相對于canvas元素的)x、y坐標(biāo)、寬度和高度。
視口坐標(biāo)的原點(diǎn)(0,0)在canvas元素的左下角,x軸和y軸的正方向分別是向右和向上,可以定義為(width-1,height-1)。
如:
var drawing = document.getElementById("drawing"); if (drawing.getContext) { try { var gl = drawing.getContext("experimental-webgl"); } catch (e) {} if (gl) { gl.clearColor(0, 0, 0, 1); gl.clear(gl.COLOR_BUFFER_BIT); // gl.viewport(0, 0, drawing.width / 2, drawing.height / 2); //視口在畫布的左下角四分之一區(qū)域 gl.viewport(drawing.width / 2, 0, drawing.width / 2, drawing.height / 2); //視口在畫布的右下角四分之一區(qū)域 } }
視口內(nèi)部的坐標(biāo)系與定義視口的坐標(biāo)系也不一樣。在視口內(nèi)部,坐標(biāo)原點(diǎn)(0,0)是視口的中心點(diǎn),因此視口左下角坐標(biāo)為(-1,-1),而右上角坐標(biāo)為(1,1)。
緩沖區(qū)頂點(diǎn)信息保存在JavaScript的類型化數(shù)組中,使用之前必須轉(zhuǎn)換到WebGL的緩沖區(qū)。要創(chuàng)建緩沖區(qū),可以調(diào)用
gl.createBuffer(),然后使用
gl.bindBuffer()綁定到WebGL上下文。這兩步做完以后,就可以用數(shù)據(jù)來填充緩沖區(qū)了。
如:
var drawing = document.getElementById("drawing"); if (drawing.getContext) { try { var gl = drawing.getContext("experimental-webgl"); } catch (e) {} if (gl) { gl.clearColor(0, 0, 0, 1); gl.clear(gl.COLOR_BUFFER_BIT); gl.viewport(drawing.width / 2, 0, drawing.width / 2, drawing.height / 2); var buffer = gl.createBuffer(); //創(chuàng)建緩沖區(qū) gl.bindBuffer(gl.ARRAY_BUFFER, buffer); //綁定到上下文 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0.5, 1]), gl.STATIC_DRAW); //使用Float32Array中的數(shù)據(jù)初始化buffer } }
gl.bufferData()
最后一個參數(shù)主要有:
gl.STATIC_DRAW:數(shù)據(jù)只加載一次,在多次繪圖中使用;
gl.STREAM_DRAW:數(shù)據(jù)只加載一次,在幾次繪圖中使用;
gl.DYNAMIC_DRAW:數(shù)據(jù)動態(tài)改變,在多次繪圖中使用;
一般來說gl.STATIC_DRAW夠用了;
在包含緩沖區(qū)的頁面重載之前,緩沖區(qū)始終保留在內(nèi)存中。如果你不想要某個緩沖區(qū)了,可以直接調(diào)用
gl.deleteBuffer()釋放內(nèi)存。
錯誤JavaScript與WebGL之間的一個最大區(qū)別在于,WebGL操作一般不會拋出錯誤。為了知道是否有錯誤發(fā)生,必須在調(diào)用某個可能出錯的方法后,手工調(diào)用
gl.getError()方法。這個方法返回一個表示錯誤類型的常量。
可能的錯誤常量如下:
gl.NO_ERROR:上一次操作沒有發(fā)生錯誤(值為0)。
gl.INVALID_ENUM:應(yīng)該給方法傳入WebGL常量,但卻傳錯了參數(shù)。
gl.INVALID_VALUE:在需要無符號數(shù)的地方傳入了負(fù)值。
gl.INVALID_OPERATION:在當(dāng)前狀態(tài)下不能完成操作。
gl.OUT_OF_MEMORY:沒有足夠的內(nèi)存完成操作。
gl.CONTEXT_LOST_WEBGL:由于外部事件(如設(shè)備斷電)干擾丟失了當(dāng)前WebGL的上下文。
如果發(fā)生了多個錯誤,需要反復(fù)調(diào)用gl.getError()直到返回gl.NO_ERROR:
var errorCode = gl.getError(); while (errorCode) { console.log(errorCode); errorCode = gl.getError(); }著色器
著色器(shader)是OpenGL 中的另一個概念。WebGL中有兩種著色器:定點(diǎn)著色器和片段(或像素)著色器。頂點(diǎn)著色器用于將3D頂點(diǎn)轉(zhuǎn)換為需要渲染的2D點(diǎn)。片段著色器用于準(zhǔn)確計算要繪制的每個像素的顏色。WebGL的著色器是使用GLSL(OpenGL Shading Language,OpenGL著色器)寫的,GLSL是一種與C和JavaScript完全不同的語言。
編寫著色器GLSL是一種類C語言,專門用于編寫OpenGL著色器。因?yàn)閃ebGL是OpenGL ES 2.0的實(shí)現(xiàn),所以O(shè)penGL中使用的著色器可以直接在WebGL中使用。
每個著色器都有一個
main()方法,該方法在繪圖期間會重復(fù)執(zhí)行。
為著色器傳遞數(shù)據(jù)的方式有兩種:
Attribute和Uniform。通過Attribute可以向頂點(diǎn)著色器傳入頂點(diǎn)信息,通過Uniform可以向任何著色器傳入常量值。
Attribute和Uniform在main()方法外部定義,分別使用關(guān)鍵字attribute和uniform。
如Attribute頂點(diǎn)著色器:
void main() { gl_Position = vec4(aVertexPosition, 0.0, 1.0); }
又如Uniform片段著色器:
void main() { gl_FragColor = uColor; }編寫著色器程序
瀏覽器不能理解GLSL程序,因此必須準(zhǔn)備好字符串形式的GLSL程序,以便編譯并鏈接到著色器程序。
為著色器傳入值前面定義的著色器必須接收一個值才能工作。為了給著色器傳入這個值,必須先找到要接收這個值的變量。
調(diào)試著色器和程序與著色器的其他操作一樣,著色器操作也可能會失敗,而且也是靜默失敗。如果你想找到著色器或程序執(zhí)行中是否發(fā)生了錯誤,必須親自詢問WebGL上下文。
繪圖WebGL只能繪制三種形狀:點(diǎn)、線和三角。其他所有形狀都是由這三種基本形狀合成之后,再繪制到三維空間中的。執(zhí)行繪圖操作要調(diào)用gl.drawArrays()或gl.drawElements()方法,前者用于數(shù)組緩沖區(qū),后置用于元素數(shù)組緩沖區(qū)。
紋理WebGL的紋理可以使用DOM中的圖像。要創(chuàng)建一個新紋理,可以調(diào)用gl.createTexture(),然后再將一副圖像綁定到該紋理。如果圖像尚未加載到內(nèi)存中,可能需要創(chuàng)建一個Image對象的實(shí)例,以便動態(tài)加載圖像。圖像加載完成之前,紋理不會初始化,因此,必須在load事件觸發(fā)后才能設(shè)置紋理。
讀取像素與2D上下文類似,通過WebGL上下文也能讀取像素值。讀取像素值的方法readPixels()與OpenGL中的同名方法只有一點(diǎn)不同,即最后一個參數(shù)必須是類型化數(shù)組。像素信息是從幀緩沖區(qū)讀取的,然后保存在類型化數(shù)組中。readPixels()方法的參數(shù)有:x、y、寬度、高度、圖像格式、數(shù)據(jù)類型和類型化數(shù)組。前4個參數(shù)指定讀取哪個區(qū)域中的像素。圖像格式參數(shù)幾乎總是gl.RGBA。數(shù)據(jù)類型用于指定保存在類型化數(shù)組中的數(shù)據(jù)類型,但有以下限制。
如果類型是gl.UNSIGNED_BYTE,則類型化數(shù)組必須是Unit8Array。
如果類型是gl.UNSIGNED_SHORT_5_6_5、gl.UNSIGNED_SHORT_4_4_4_4、或gl.UNSIGNED_SHORT_5_5_5_1,則類型化數(shù)組必須是Unit16Array。
15.3.3 支持
Firefox4+和Chrome都實(shí)現(xiàn)了WebGL API。Safari5.1也實(shí)現(xiàn)了WebGL,但默認(rèn)是禁用的。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/78634.html
摘要:在文末,我會附上一個可加載的模型方便學(xué)習(xí)中文藝術(shù)字渲染用原生可以很容易地繪制文字,但是原生提供的文字效果美化功能十分有限。 showImg(https://segmentfault.com/img/bVWYnb?w=900&h=385); WebGL 可以說是 HTML5 技術(shù)生態(tài)鏈中最為令人振奮的標(biāo)準(zhǔn)之一,它把 Web 帶入了 3D 的時代。 初識 WebGL 先通過幾個使用 Web...
摘要:源圖像之外的目標(biāo)圖像部分不會被顯示。使用異或操作對源圖像與目標(biāo)圖像進(jìn)行組合。如將第二個圖片放在第一個圖片下方檢查兼容性繪制原始圖像 Canvas支持基本繪圖能力的2D上下文,以及基于WebGL的3D上下文 基本用法 canvas元素:定義畫布 getContext()方法:定義2D、3D上下文 toDataURL()方法:生成圖片格式獲取URL鏈接(支持image/png;有瀏覽器也...
摘要:支持動畫狀態(tài)的,在動畫開始,執(zhí)行中,結(jié)束時提供回調(diào)函數(shù)支持動畫可以自定義貝塞爾曲線任何包含數(shù)值的屬性都可以設(shè)置動畫倉庫文檔演示功能介紹一定程度上,也是一個動畫庫,適用所有的屬性,并且實(shí)現(xiàn)的能更方便的實(shí)現(xiàn)幀動畫,替代復(fù)雜的定義方式。 動畫調(diào)研-V1 前言:動畫從用途上可以分為兩種,一種是展示型的動畫,類似于一張GIF圖,或者一段視頻,另一種就是交互性的動畫。這兩種都有具體的應(yīng)用場景,比如...
閱讀 2093·2021-11-22 13:52
閱讀 1024·2021-11-17 09:33
閱讀 2740·2021-09-01 10:49
閱讀 2876·2019-08-30 15:53
閱讀 2684·2019-08-29 16:10
閱讀 2456·2019-08-29 11:31
閱讀 1399·2019-08-26 11:40
閱讀 1906·2019-08-26 10:59