webgl入門指南(一)

一、前言
本文基于MDN技術文檔:

https://developer.mozilla.org/zh-CN/docs/Web/API/WebGL_API

    WebGL 是基于 OpenGL ES 規(guī)范的瀏覽器實現的JavaScript API 。能在任何兼容的Web瀏覽器中渲染高性能的交互式3D和2D圖形。
可以在HTML5 <canvas>元素中使用。
二、基于webgl的開發(fā)的庫有哪些
    業(yè)界有很多基于WebGL開發(fā)了一些庫,這里廣東靚仔列舉了一些:

基于webGL開發(fā)的庫

1、three.js 開源的,功能齊全的3D WebGL庫

2、RedGL 是一個開源3D WebGL庫 (韓國)

3、vtk.js 是一個JavaScript庫,用于在瀏覽器中進行科學可視

4、babylon.js 基于WebGL的圖形引擎

5、Hightopo組件豐富,非開源的付費項目


Three.js的Demo圖片預覽




















基于Three.js

三、WebGL繪制圖形的5個流程
創(chuàng)建 WebGL 上下文

創(chuàng)建 WebGL 程序(WebGLProgram)

將數據存入緩沖區(qū)

將緩沖區(qū)數據讀取到 GPU

GPU 執(zhí)行 WebGL 程序,輸出結果

我們來看看流程圖:





    下面我們通過一個Demo來講解下,這里看不懂的小伙伴不著急,看完Demo回頭再看看,會更容易理解。

四、Demo
html
<canvas width="300" height="300"></canvas>
js
html跟Canvas2D一樣,我們使用<canvas>元素就可以了

// 調用canvas元素
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
// 倆個著色器
const vertex = `
  // 將緩沖區(qū)數據讀取到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 色值表示的四維向量數據
      gl_FragColor = vec4(color, 1.0);
  }
`
// 頂點著色器  片元著色器
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并關聯兩個shader
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
 
// 啟用program
gl.useProgram(program);
 
// 定義三個頂點,類型化數組
const points =  new Float32Array([ -1, -1, 0, 1, 1, -1,])
// 定義好的數組寫入緩沖區(qū)
const bufferId = gl.createBuffer(); // 創(chuàng)建緩沖區(qū)對象
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId); // 將緩沖區(qū)對象綁定到目標
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW) // 將數據寫入緩沖區(qū)對象
 
 
// 獲取頂點著色器中的position變量的地址
const vPosition = gl.getAttribLocation(program, 'position');
// 給變量設置長度和類型
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
// 激活這個變量
gl.enableVertexAttribArray(vPosition);
 
// 執(zhí)行著色器完成繪制
gl.clear(gl.COLOR_BUFFER_BIT); // 清空<canvas>
gl.drawArrays(gl.TRIANGLES, 0, points.length / 2); // 繪制三角形
效果如下












demo詳解
創(chuàng)建 WebGL直接調用 canvas 元素的 getContext 即可
將參數從2d換成webgl,代碼如下:

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl')
從效果圖我們可以看到由三個頂點,繪制成一個三角形。
WebGL就是以頂點和圖元來繪制幾何圖形的。
頂點容易理解,圖元是 WebGL
可直接處理的圖形單元,具體的有7種:

點 gl.POINTS

線段 gl.LINES

線條 gl.LINE_STRIP

回路 gl.LINE_LOOP

三角形 gl.TRIANGLES

三角帶 gl.TRIANGLE_STRIP

三角扇 gl.TRIANGLE_FAN

復雜的圖形就是由這7個圖元拼成的。

效果圖里面三角形的顏色就是由頂點著色器、片元著色器處理的。
頂點著色器:它可以改變頂點的信息,從而改變我們繪制出來的圖形的形狀或者大小等等。
片元著色器:處理光柵化后的像素信息。
光柵化:從頂點著色器和圖元提取像素點給片元著色器執(zhí)行代碼的過程。

我們結合代碼來理解這概念


頂點著色器和片元著色器代碼片段

  // 頂點著色器
  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 對象的創(chuàng)建過程主要是添加 vertexShader 和 fragmentShader,然后將這個 WebGLProgram 對象鏈接到 WebGL 上下文對象上

// 創(chuàng)建program并關聯兩個shader
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);


啟用這個 WebGLProgram 對象

// 啟用program
gl.useProgram(program);


定義好的數據寫入 WebGL 的緩沖區(qū)

// 定義三個頂點,類型化數組
const points =  new Float32Array([ -1, -1, 0, 1, 1, -1,])
// 定義好的數組寫入緩沖區(qū)
const bufferId = gl.createBuffer(); // 創(chuàng)建緩沖區(qū)對象
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId); // 將緩沖區(qū)對象綁定到目標
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW) // 將數據寫入緩沖區(qū)對象
上面代碼中,Float32Array,是一個類型化數組。含義即類型化數組對象描述了一個底層的二進制數據緩沖區(qū)(binary data buffer)的一個類數組視圖(view)。


頂點著色器

// 將緩沖區(qū)數據讀取到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 是變量的類型,它表示一個二維向量、三維向量,position 是變量名。


把數據綁定給頂點著色器中的 position 變量

// 獲取頂點著色器中的position變量的地址
const vPosition = gl.getAttribLocation(program, 'position');
// 給變量設置長度和類型
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
// 激活這個變量
gl.enableVertexAttribArray(vPosition);


執(zhí)行著色器程序來完成繪制

// 執(zhí)行著色器完成繪制
gl.clear(gl.COLOR_BUFFER_BIT); // 清空<canvas>
gl.drawArrays(gl.TRIANGLES, 0, points.length / 2); // 繪制三角形
先調用 gl.clear 將當前畫布的內容清除,然后調用gl.drawArrays。gl.drawArrays里參數分別表示:
gl.TRIANGLES 表示以三角形為圖元繪制、繪制的頂點偏移量、頂點數量

webgl其他知識
1、顏色
2、圖案
3、紋理
3、3d(vec3三維)
4、相機
5、光照


五、總結
    在我們閱讀完官方文檔后,我們要深入學習,可以著重去掌握以下內容:
坐標系轉換
參數方程(圓錐曲線、貝塞爾曲線(二、三階))
向量(叉乘、點乘)
矩陣

作者:廣東靚仔


歡迎關注:前端早茶