掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
大家好,我是前端西瓜哥。

本文講解如何用 WebGL 繪制一個點(diǎn)。
WebGL 是瀏覽器支持的一種繪制圖形的 API,是一個標(biāo)準(zhǔn)。我們可以通過 Canvas 元素 在網(wǎng)頁的特定區(qū)域繪制 2D 和 3D 圖形。
相比 Canvas 2D,WebGL 利用了 GPU 的計算能力,繪制速度更快,性能更優(yōu)。
WebGL 基于 OpenGL 發(fā)展而來,某種意義上就是 Web 版的 OpenGL,但是閹割了一些功能。
更具體點(diǎn),是來自 OpenGL 的一個特殊版本 OpenGL ES 2.0,全稱為 OpenGL for Embedded Systems,“用于嵌入式系統(tǒng)的 OpenGL”。
使用 WebGL,除了瀏覽器正統(tǒng)腳本語言 JavaScript,還要使用一種 名為 GLSL ES 的類 C 著色器語言。
將代碼描述的效果真正繪制到屏幕上的過程,稱為 渲染管線。
管線(pipeling)這個詞有點(diǎn)奇怪,因為它沒有對應(yīng)的比較好的翻譯,是一個直譯。
管線指的是 數(shù)據(jù)處理的流水線,這個流水線上有很多處理器,會將數(shù)據(jù)一步步地進(jìn)行處理,最終得到一個成品。渲染管線,就是渲染過程中執(zhí)行的一個個步驟。
渲染管線的流程為:
這四個流程中,我們能操作的是第 1 和第 4 步。
Demo 地址:
https://codesandbox.io/s/webgl-hui-zhi-yi-ge-dian-2-bpwz8p。
下面我們來講解如何繪制一個點(diǎn)。
首先是 WebGL 繪制的地方 Canvas。我們需要在 HTML 中添加一個 Canvas 元素,然后在 JavaScript 中獲取這個元素,并拿到 WebGL 渲染上下文。
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl");如果你用過 Canvas 2D,它對應(yīng)的上下文變量命名通常是 ctx(context)。但對于 WebGL,我們通常會跟隨 OpenGL 的習(xí)慣,將變量命名為 gl(OpenGL 的 gl,Graphics Library 的意思)。
接著是頂點(diǎn)著色器。
頂點(diǎn)著色器,用于設(shè)置圖形的頂點(diǎn)相關(guān)的信息,設(shè)置好頂點(diǎn),WebGL 才能確定好圖形的位置等信息,好繪制出來。
著色器的代碼是在 JavaScript 腳本中,用字符串來寫 glsl。
先是頂點(diǎn)著色器。
const vertexShaderSrc = `
void main() {
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
gl_PointSize = 20.0;
}
`;
gl_Postion 和 gl_PointSize 是 WebGL 頂點(diǎn)著色器的內(nèi)部變量,用于設(shè)置點(diǎn)的位置和點(diǎn)的大小。
vec4 表示矢量類型,同時也是內(nèi)置函數(shù),調(diào)用它就能得到一個 vec4 類型。
這里設(shè)置了頂點(diǎn)的位置 (0.0, 0.0, 0.0, 1.0)。WebGL 使用的是三維坐標(biāo)系,并使用右手坐標(biāo)系,就是 x 軸指向右側(cè),y 軸指向上方,z 軸指向觀察者。原點(diǎn)就在畫布的正中央。
三維中,一個點(diǎn)只要三個維度 x、y、z 就夠了,但引入了第四個維度 w,從笛卡爾坐標(biāo)升維為齊次坐標(biāo),作用是方便做矩陣變換和透視投影。齊次坐標(biāo) ??(x, y, z, w)??? 等價于三維坐標(biāo) ??(x/w, y/w, z/w)??。w 通常會設(shè)置為 1。
需要注意的是,著色器中的的數(shù)值需要加上小數(shù)點(diǎn),表示用的是浮點(diǎn)數(shù)類型。這和 JavaScript 隨便寫都會變成浮點(diǎn)數(shù)不一樣。
然后是片元著色器。
頂點(diǎn)著色器確定圖形的點(diǎn)的位置,片元著色器則是用于設(shè)置多個頂點(diǎn)圍成的圖形的像素點(diǎn)的 顏色。
const fragmentShaderSrc = `
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
gl_FragColor 是片元著色器的內(nèi)部變量,這里設(shè)置為紅色。
因為是入門文章,細(xì)節(jié)不展開講了。
總之下面這段代碼,將前面聲明的頂點(diǎn)著色器和片元著色器的兩段源碼,進(jìn)行了編譯。
/**** 渲染器生成處理 ****/
// 創(chuàng)建頂點(diǎn)渲染器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSrc);
gl.compileShader(vertexShader);
// 創(chuàng)建片元渲染器
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSrc);
gl.compileShader(fragmentShader);
// 程序?qū)ο?br>const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
gl.program = program;
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
首先第一行代碼將背景色設(shè)置為黑色。當(dāng)然你也可以設(shè)置為其他顏色,比如綠色 (0, 1, 0, 1)。
第二行是清空緩存區(qū),填充背景色。
gl.drawArrays(gl.POINTS, 0, 1);
該 API 用于調(diào)用繪制指令,有三個參數(shù):
繪制結(jié)果如下:
下一篇畫個三角形。

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流