WebGL(Web Graphics Library)是一種基于 OpenGL ES 2.0 的 JavaScript API,用于在網頁上實現高性能的 3D 圖形渲染。
1. 初始化 WebGL 上下文
在使用 WebGL 之前,需要獲取<canvas>
元素并創建 WebGL 上下文。
// 獲取canvas
const canvas = document.querySelector('canvas');
// 獲取webgl上下文對象,注意選擇webgl的1.0版本,2.0版本有一些語法不一樣
const gl = canvas.getContext('webgl');
document.querySelector('canvas')
:通過選擇器獲取 HTML 文檔中的<canvas>
元素。canvas.getContext('webgl')
:獲取<canvas>
元素的 WebGL 上下文。如果瀏覽器不支持 WebGL,該方法將返回null
。
2. 著色器編程
WebGL 使用著色器(Shader)來處理圖形渲染的各個階段。著色器是運行在 GPU 上的小程序,主要分為頂點著色器(Vertex Shader)和片元著色器(Fragment Shader)。
import fragShader from '../shader/2.webgl繪制點/fragShader.glsl';
import vertexShader from '../shader/2.webgl繪制點/vertexShader.glsl';
import { initShader } from '../lib';// fragShader和vertexShader引入之后是字符串,需要被編譯為可執行的程序
const program = initShader(gl, vertexShader, fragShader);
- 頂點著色器(Vertex Shader):負責處理每個頂點的位置、顏色等屬性。
- 片元著色器(Fragment Shader):負責處理每個像素的顏色。
initShader
函數:用于初始化著色器,創建并配置程序對象。
export function initShader(gl, vshader_source, fshader_source) {// 創建著色器const vertexShader = createShaderFromString(gl,gl.VERTEX_SHADER,vshader_source);const fragmentShader = createShaderFromString(gl,gl.FRAGMENT_SHADER,fshader_source);// 創建一個程序對象 操作手,專門負責javaScript和shader著色器的通訊const program = gl.createProgram();gl.attachShader(program, vertexShader);gl.attachShader(program, fragmentShader);// 將javascrpt和程序對象關聯gl.linkProgram(program);// 使用程序對象gl.useProgram(program);// 返回程序對象return program;
}
gl.createShader(type)
:創建一個指定類型的著色器對象(gl.VERTEX_SHADER
或gl.FRAGMENT_SHADER
)。gl.shaderSource(shader, source)
:將著色器源代碼賦值給著色器對象。gl.compileShader(shader)
:編譯著色器對象。gl.createProgram()
:創建一個程序對象,用于管理著色器。gl.attachShader(program, shader)
:將著色器對象附加到程序對象上。gl.linkProgram(program)
:鏈接程序對象,將頂點著色器和片元著色器關聯起來。gl.useProgram(program)
:使用指定的程序對象進行渲染。
3. 緩沖區對象
緩沖區對象(Buffer Object)用于在 CPU 和 GPU 之間傳遞數據,如頂點坐標、顏色等。
// 1.創建頂點數據對象
const vertices = new Float32Array([0, 0.5,-0.5, -0.5,0.5, -0.5,
]);// 2.創建緩沖區對象
const buffer = gl.createBuffer();// 3.綁定緩沖區對象的用途
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);// 4.向緩沖區中寫入數據
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);// 5.設置attribute變量對緩沖區的訪問規則
const a_Position = gl.getAttribLocation(program, 'a_Position');
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);// 6.啟動數據讀取
gl.enableVertexAttribArray(a_Position);
gl.createBuffer()
:創建一個緩沖區對象。gl.bindBuffer(target, buffer)
:將緩沖區對象綁定到指定的目標(gl.ARRAY_BUFFER
用于存儲頂點數據)。gl.bufferData(target, data, usage)
:向緩沖區對象中寫入數據。usage
參數指定數據的使用方式,gl.STATIC_DRAW
表示數據不會頻繁更改。gl.getAttribLocation(program, name)
:獲取頂點著色器中attribute
變量的位置。gl.vertexAttribPointer(index, size, type, normalized, stride, offset)
:設置attribute
變量對緩沖區的訪問規則。index
:attribute
變量的位置。size
:每個頂點的分量個數。type
:數據的類型,如gl.FLOAT
。normalized
:是否需要歸一化。stride
:連續頂點屬性之間的間隔。offset
:頂點屬性在數組中的偏移量。
gl.enableVertexAttribArray(index)
:啟用指定位置的attribute
變量。
4. 繪制圖形
使用gl.drawArrays
或gl.drawElements
方法繪制圖形。
// 最后調用drawArrays繪制,這里可以將count取3,一次繪制三個點
gl.drawArrays(gl.POINTS, 0, 3);
gl.drawArrays(mode, first, count)
:從指定位置開始,繪制指定數量的頂點。mode
:繪制模式,如gl.POINTS
(點)、gl.LINES
(線)、gl.TRIANGLES
(三角形)等。first
:從第幾個頂點開始繪制。count
:要繪制的頂點數量。
5. 深度檢測
深度檢測用于判斷物體的正確遮擋關系。
// 深度檢測,用來判斷物體的正確遮擋關系
gl.enable(gl.DEPTH_TEST);
gl.enable(capability)
:啟用指定的功能,gl.DEPTH_TEST
表示啟用深度檢測。
6. 相機和投影矩陣
在 3D 場景中,需要使用相機和投影矩陣來定義視角和投影方式。
import { mat4 } from 'gl-matrix';
import PerspectiveCamera from '../lib/PerspectiveCamera';// viewMatrix的參數
const vModelView = {viewX: 0,viewY: 0,viewZ: 1,lookAtX: 0,lookAtY: 0,lookAtZ: 0,
};const vModelProj = {fov: 45,aspect: 1,near: 0.1,far: 4,
};
const camera = new PerspectiveCamera(gl, program, {fov: vModelProj.fov,aspect: vModelProj.aspect,near: vModelProj.near,far: vModelProj.far,lookAt: [vModelView.lookAtX, vModelView.lookAtY, vModelView.lookAtZ],position: [vModelView.viewX, vModelView.viewY, vModelView.viewZ],up: [0, 1, 0],
});// 創建視圖矩陣
const createViewMatrix = () => {const viewMatrix = mat4.create();// 創建視圖矩陣,三個參數,相機位置,注視的坐標,上方向mat4.lookAt(viewMatrix,[vModelView.viewX, vModelView.viewY, vModelView.viewZ],[vModelView.lookAtX, vModelView.lookAtY, vModelView.lookAtZ],[0, 1, 0]);gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix);
};// 創建投影矩陣
const createProjMatrix = () => {const projMatrix = mat4.create();// 創建正交投影矩陣mat4.perspectiveNO(projMatrix, ...Object.values(vModelProj));gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix);
};
PerspectiveCamera
:自定義的透視相機類,用于管理相機的屬性和矩陣。mat4.create()
:創建一個 4x4 的矩陣。mat4.lookAt(out, eye, center, up)
:創建視圖矩陣,指定相機的位置、注視點和上方向。mat4.perspectiveNO(out, fovy, aspect, near, far)
:創建透視投影矩陣。gl.uniformMatrix4fv(location, transpose, value)
:將矩陣數據傳遞給著色器中的uniform
變量。
7. 光照效果
在 WebGL 中,可以實現不同類型的光照效果,如環境光、漫反射光和鏡面高光。
import AmbientLight from '../lib/Light/AmbientLight';
import DiffuseLight from '../lib/Light/DiffuseLight';
import SpecularLight from '../lib/Light/SpecularLight';const vModel = {color: 0xffffff,intensity: 1
};
const vModelDiffuse = {color: 0xffffff,intensity: 1
};
const light = new AmbientLight(gl, program, vModel);
const diffuseLight = new DiffuseLight(gl, program, vModelDiffuse);
const specularLight = new SpecularLight(gl, program);
AmbientLight
:環境光類,用于模擬全局光照效果。DiffuseLight
:漫反射光類,用于模擬物體表面的漫反射光照效果。SpecularLight
:鏡面高光類,用于模擬物體表面的鏡面反射光照效果。
8. GUI 交互
使用dat.gui
庫可以創建簡單的圖形用戶界面,方便調試和交互。
import * as dat from 'dat.gui';const gui = new dat.GUI();
const vModel = {scale: 1,angle: 0,tx: 0,ty: 0
};gui.add(vModel, 'scale', 0.1, 2).step(0.1).name('縮放').onChange(render);
gui.add(vModel, 'angle', 0, 360).step(1).name('旋轉').onChange(render);
gui.add(vModel, 'tx', -1, 1).step(0.1).name('x軸平移').onChange(render);
gui.add(vModel, 'ty', -1, 1).step(0.1).name('y軸平移').onChange(render);
dat.GUI()
:創建一個 GUI 對象。gui.add(object, property, min, max, step)
:添加一個滑塊控件,用于控制對象的屬性。onChange(callback)
:當控件的值發生變化時,調用回調函數。