webgl入門指南(一)
一、前言
本文基于MDN技術(shù)文檔:
https://developer.mozilla.org/zh-CN/docs/Web/API/WebGL_API
WebGL 是基于 OpenGL ES 規(guī)范的瀏覽器實(shí)現(xiàn)的JavaScript API 。能在任何兼容的Web瀏覽器中渲染高性能的交互式3D和2D圖形。
可以在HTML5 <canvas>元素中使用。
二、基于webgl的開發(fā)的庫有哪些
業(yè)界有很多基于WebGL開發(fā)了一些庫,這里廣東靚仔列舉了一些:
基于webGL開發(fā)的庫
1、three.js 開源的,功能齊全的3D WebGL庫
2、RedGL 是一個(gè)開源3D WebGL庫 (韓國(guó))
3、vtk.js 是一個(gè)JavaScript庫,用于在瀏覽器中進(jìn)行科學(xué)可視
4、babylon.js 基于WebGL的圖形引擎
5、Hightopo組件豐富,非開源的付費(fèi)項(xiàng)目
Three.js的Demo圖片預(yù)覽
基于Three.js
三、WebGL繪制圖形的5個(gè)流程
創(chuàng)建 WebGL 上下文
創(chuàng)建 WebGL 程序(WebGLProgram)
將數(shù)據(jù)存入緩沖區(qū)
將緩沖區(qū)數(shù)據(jù)讀取到 GPU
GPU 執(zhí)行 WebGL 程序,輸出結(jié)果
我們來看看流程圖:
下面我們通過一個(gè)Demo來講解下,這里看不懂的小伙伴不著急,看完Demo回頭再看看,會(huì)更容易理解。
四、Demo
html
<canvas width="300" height="300"></canvas>
js
html跟Canvas2D一樣,我們使用<canvas>元素就可以了
// 調(diào)用canvas元素
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
// 倆個(gè)著色器
const vertex = `
// 將緩沖區(qū)數(shù)據(jù)讀取到GPU
attribute vec2 position; // 聲明變量名威position的二維向量
varying vec3 color;
void main () {
gl_PointSize = 1.0;
color = vec3(0.5 + position * 0.5, 0.0);
gl_Position = vec4(position * 0.5, 1.0, 1.0);
}
`
const fragment = `
precision mediump float;
varying vec3 color;
void main () {
// RGBA 色值表示的四維向量數(shù)據(jù)
gl_FragColor = vec4(color, 1.0);
}
`
// 頂點(diǎn)著色器 片元著色器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertex);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragment);
gl.compileShader(fragmentShader);
// 創(chuàng)建program并關(guān)聯(lián)兩個(gè)shader
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
// 啟用program
gl.useProgram(program);
// 定義三個(gè)頂點(diǎn),類型化數(shù)組
const points = new Float32Array([ -1, -1, 0, 1, 1, -1,])
// 定義好的數(shù)組寫入緩沖區(qū)
const bufferId = gl.createBuffer(); // 創(chuàng)建緩沖區(qū)對(duì)象
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId); // 將緩沖區(qū)對(duì)象綁定到目標(biāo)
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW) // 將數(shù)據(jù)寫入緩沖區(qū)對(duì)象
// 獲取頂點(diǎn)著色器中的position變量的地址
const vPosition = gl.getAttribLocation(program, 'position');
// 給變量設(shè)置長(zhǎng)度和類型
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
// 激活這個(gè)變量
gl.enableVertexAttribArray(vPosition);
// 執(zhí)行著色器完成繪制
gl.clear(gl.COLOR_BUFFER_BIT); // 清空<canvas>
gl.drawArrays(gl.TRIANGLES, 0, points.length / 2); // 繪制三角形
效果如下
demo詳解
創(chuàng)建 WebGL直接調(diào)用 canvas 元素的 getContext 即可
將參數(shù)從2d換成webgl,代碼如下:
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl')
從效果圖我們可以看到由三個(gè)頂點(diǎn),繪制成一個(gè)三角形。
WebGL就是以頂點(diǎn)和圖元來繪制幾何圖形的。
頂點(diǎn)容易理解,圖元是 WebGL
可直接處理的圖形單元,具體的有7種:
點(diǎn) gl.POINTS
線段 gl.LINES
線條 gl.LINE_STRIP
回路 gl.LINE_LOOP
三角形 gl.TRIANGLES
三角帶 gl.TRIANGLE_STRIP
三角扇 gl.TRIANGLE_FAN
復(fù)雜的圖形就是由這7個(gè)圖元拼成的。
效果圖里面三角形的顏色就是由頂點(diǎn)著色器、片元著色器處理的。
頂點(diǎn)著色器:它可以改變頂點(diǎn)的信息,從而改變我們繪制出來的圖形的形狀或者大小等等。
片元著色器:處理光柵化后的像素信息。
光柵化:從頂點(diǎn)著色器和圖元提取像素點(diǎn)給片元著色器執(zhí)行代碼的過程。
我們結(jié)合代碼來理解這概念
頂點(diǎn)著色器和片元著色器代碼片段
// 頂點(diǎn)著色器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertex);
gl.compileShader(vertexShader);
// 片元著色器
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragment);
gl.compileShader(fragmentShader);
WebGLProgram 對(duì)象的創(chuàng)建過程主要是添加 vertexShader 和 fragmentShader,然后將這個(gè) WebGLProgram 對(duì)象鏈接到 WebGL 上下文對(duì)象上
// 創(chuàng)建program并關(guān)聯(lián)兩個(gè)shader
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
啟用這個(gè) WebGLProgram 對(duì)象
// 啟用program
gl.useProgram(program);
定義好的數(shù)據(jù)寫入 WebGL 的緩沖區(qū)
// 定義三個(gè)頂點(diǎn),類型化數(shù)組
const points = new Float32Array([ -1, -1, 0, 1, 1, -1,])
// 定義好的數(shù)組寫入緩沖區(qū)
const bufferId = gl.createBuffer(); // 創(chuàng)建緩沖區(qū)對(duì)象
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId); // 將緩沖區(qū)對(duì)象綁定到目標(biāo)
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW) // 將數(shù)據(jù)寫入緩沖區(qū)對(duì)象
上面代碼中,F(xiàn)loat32Array,是一個(gè)類型化數(shù)組。含義即類型化數(shù)組對(duì)象描述了一個(gè)底層的二進(jìn)制數(shù)據(jù)緩沖區(qū)(binary data buffer)的一個(gè)類數(shù)組視圖(view)。
頂點(diǎn)著色器
// 將緩沖區(qū)數(shù)據(jù)讀取到GPU
attribute vec2 position; // 聲明變量名position的二維向量
varying vec3 color;
void main () {
gl_PointSize = 1.0;
color = vec3(0.5 + position * 0.5, 0.0);
gl_Position = vec4(position * 0.5, 1.0, 1.0);
}
attribute 表示聲明變量,vec2、vec3 是變量的類型,它表示一個(gè)二維向量、三維向量,position 是變量名。
把數(shù)據(jù)綁定給頂點(diǎn)著色器中的 position 變量
// 獲取頂點(diǎn)著色器中的position變量的地址
const vPosition = gl.getAttribLocation(program, 'position');
// 給變量設(shè)置長(zhǎng)度和類型
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
// 激活這個(gè)變量
gl.enableVertexAttribArray(vPosition);
執(zhí)行著色器程序來完成繪制
// 執(zhí)行著色器完成繪制
gl.clear(gl.COLOR_BUFFER_BIT); // 清空<canvas>
gl.drawArrays(gl.TRIANGLES, 0, points.length / 2); // 繪制三角形
先調(diào)用 gl.clear 將當(dāng)前畫布的內(nèi)容清除,然后調(diào)用gl.drawArrays。gl.drawArrays里參數(shù)分別表示:
gl.TRIANGLES 表示以三角形為圖元繪制、繪制的頂點(diǎn)偏移量、頂點(diǎn)數(shù)量
webgl其他知識(shí)
1、顏色
2、圖案
3、紋理
3、3d(vec3三維)
4、相機(jī)
5、光照
等
五、總結(jié)
在我們閱讀完官方文檔后,我們要深入學(xué)習(xí),可以著重去掌握以下內(nèi)容:
坐標(biāo)系轉(zhuǎn)換
參數(shù)方程(圓錐曲線、貝塞爾曲線(二、三階))
向量(叉乘、點(diǎn)乘)
矩陣
作者:廣東靚仔
歡迎關(guān)注:前端早茶