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