以前一直在搗鼓Vue和React棧,對組件化架構項目有了些理解和體會。今天嚐嚐WebGL,固然,並不打算如今深刻,只是略做了解,我知道這個坑很深。css
js的圖形庫、3d庫也有好幾款比較流行的,如遊戲開發方面的three.js、數據可視化的圖表庫echarts.js、GIS方面的百度地圖、google地圖等,最近打算學習下。html
言歸正傳,之前學canvas的時候,只是簡單地學習2d context的一些api寫寫畫畫,webGL顯然更高級些,在MDN文檔的介紹中:web
WebGL enables web content to use an API based on OpenGL ES 2.0 to perform 3D rendering in an HTML
<canvas>
in browsers that support it without the use of plug-ins. WebGL programs consist of control code written in JavaScript and special effects code(shader code) that is executed on a computer's Graphics Processing Unit (GPU). WebGL elements can be mixed with other HTML elements and composited with other parts of the page or page background.編程
提到了WebGL可讓網頁內容中的canvas元素實現3d渲染,其編程由兩部分組成,一部分是由js寫的控制代碼,一部分是在用戶設備gpu上執行的實現特定效果的代碼(GLSL,注意,GLSL是一門針對GPU的編程語言)。不過WebGL只兼容IE11+canvas
教程假設咱們會一些基本的3d圖像的概念。Learn WebGL for 2D and 3D graphics這篇入門教程指出,須要咱們會一點html和css知識,以及較深的js功底,能理解閉包、原型鏈、構造函數等概念。api
第一步,檢測設備是否支持WebGL:閉包
function detectWebGLContext () { // Create canvas element. The canvas is not added to the // document itself, so it is never displayed in the // browser window. var canvas = document.createElement("canvas"); // Get WebGLRenderingContext from canvas element. var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); // Report the result. if (gl && gl instanceof WebGLRenderingContext) { paragraph.innerHTML = "Congratulations! Your browser supports WebGL."; } else { paragraph.innerHTML = "Failed to get WebGL context. " + "Your browser or device may not support WebGL."; } }
跟通常的功能檢測同樣,其實就是判斷 gl = canvas.getContext("webgl")|| canvas.getContext("experimental-webgl") 是否是 WebGLRenderingContext 的一個實例。一旦咱們的canvas元素有這個rendering context,咱們就可使用它的api進行渲染。架構
第二步,開始簡單的exampleecharts
-----填充WebGLContextdom
1.獲取(set up)rendering context ,就是上一步的gl。
2.而後drawing buffer(如今先理解爲畫布)填充顏色。這個過程分兩步:
//肯定渲染的範圍 gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); //設定WebGL的內部狀態--設定顏色 // Set the clear color to darkish green. gl.clearColor(0.0, 0.5, 0.0, 1.0); //輸出其狀態--填充顏色 // Clear the context with the newly set color. This is // the function call that actually does the drawing. gl.clear(gl.COLOR_BUFFER_BIT);
gl.viewport()中前兩個參數是相對於左下角的距離。後兩個是寬,高。
在定義了drawing buffer的 範圍後,咱們執行了兩個動做,先是設定WebGL的內部狀態(顏色爲綠色),而後執行語句讓drawing buffer 變成WebGL內部狀態所設定的樣子。因此,WebGL其實是一個狀態機。咱們能夠回想下,在getContext(「2d」)的時候,要畫一個矩形,咱們也是遵循一樣的操做步驟:
//定義樣式(即內部狀態) cxt.fillStyle="#FF0000"; //輸出圖形(將樣式狀態輸出到畫布中) cxt.fillRect(0,0,150,75);
最後,WebGL中顏色定義都是使用RGBA格式的。
-----開始將WebGL和用戶交互結合
Clearing by clicking一例由上面的簡單例子延伸而來,對canvas和button綁定了click事件,觸發switchColor函數。
該函數先判斷是否支持WebGL,再肯定畫布的範圍,以後再執行三行代碼:
//產生隨機顏色 // Get a random color value using a helper function. var color = getRandomColor(); //設置WebGL內部狀態的顏色新值 // Set the clear color to the random color. gl.clearColor(color[0], color[1], color[2], 1.0); //將新值輸出到畫布 // Clear the context with the newly set color. This is // the function call that actually does the drawing. gl.clear(gl.COLOR_BUFFER_BIT);
----裁剪:
//開啓裁剪功能 // Enable scissoring operation and define the position and // size of the scissoring area. gl.enable(gl.SCISSOR_TEST); //設定可更新的區域 gl.scissor(60, 60, 60, 130); // Clear the drawing buffer solid yellow. gl.clearColor(1.0, 0.6, 0.0, .1); gl.clear(gl.COLOR_BUFFER_BIT);
getContext("2d")中也有類似的api。只有在指定的區域中畫布纔會被更新(顯示)。
----不設置高寬會致使不符合預期的渲染結果
咱們知道設置css能夠改變元素的視覺高寬,canvas也同樣。但若是咱們只是單純設置了css樣式,不對其dom節點設置高寬,將致使詭異的渲染效果。
其實不止「webgl」的RenderingConext,「2d」的context也會有這種狀況。
之前研究過canvas這個問題,由於css只是改變canvas元素呈如今頁面上的視覺大小,可是其邏輯像素默認是300*150.
當咱們調用api時,往api中傳入表示高寬或x、y軸位置的參數時,一旦超出y軸方向的150和x軸方向的300,就會超出畫布。
因此必要的時候,咱們得獲取canvas節點,而後js設定其邏輯高寬。canvas.height=xx;canvas.width=xx;
----封裝WebGL 方法
function getRenderingContext() { var canvas = document.querySelector("canvas"); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); if (!gl) { var paragraph = document.querySelector("p"); paragraph.innerHTML = "Failed to get WebGL context." + "Your browser or device may not support WebGL."; return null; } gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); return gl; }
這一節沒什麼新內容,只是把幾個基本的語句進行封裝。函數作了兩件事情,判斷是否支持webgl,而後將畫布填充成黑色並返回RenderingContext這個接口。
//往後補充