🧮 gl-matrix矩阵库全API详解(WebGIS专属优化版)
gl-matrix是专为WebGL设计的轻量级、高性能线性代数库 ,核心优势是基于Float32Array存储数据(与WebGL原生兼容)、纯函数式设计、无依赖,是Cesium/Mapbox等WebGIS框架的底层矩阵运算核心。以下从向量、矩阵、四元数三大模块,结合WebGIS场景详解所有核心API。
📌 基础概念与通用规则
1. 核心特性
- 列主序存储 :矩阵采用WebGL原生的列主序格式,直接传递给
gl.uniformMatrix4fv()无需转置 - 纯函数设计:所有函数均为纯函数,避免副作用,结果存储到目标数组(第一个参数),减少内存分配
- 性能优先 :复用目标数组(
out参数)避免频繁创建新对象,运算速度比普通数组快3-5倍 - GIS适配:完美支持地理坐标变换、投影矩阵、三维姿态控制等WebGIS核心需求
2. 通用API模式
绝大多数函数遵循:
javascript
fn(out: Float32Array, a: Float32Array, b: Float32Array, ...args) → Float32Array
out:目标数组,用于存储运算结果,避免创建新对象a/b:输入数组(向量/矩阵)- 返回值:与
out同一引用,支持链式调用
一、向量模块(vec2/vec3/vec4)
用于存储坐标、方向、颜色等n维数据,vec3是WebGIS中最常用的(三维地理坐标、法向量),vec2用于二维投影坐标,vec4用于齐次坐标。
1. 创建与复制API
| API名称 | 作用 | 示例 |
|---|---|---|
vecN.create() |
创建空的N维向量,初始值为[0,0,...] |
const pos = vec3.create(); // [0,0,0] |
vecN.fromValues(x,y,...) |
从数值直接创建N维向量 | const beijing = vec3.fromValues(116.4, 39.9, 0); // 北京经纬度 |
vecN.copy(out, a) |
复制向量a到out |
vec3.copy(outPos, beijing); // outPos = [116.4,39.9,0] |
vecN.set(out, x,y,...) |
直接设置向量out的数值 |
vec3.set(outPos, 121.5, 31.2, 0); // 上海坐标 |
2. 基础运算API
| API名称 | 作用 | GIS场景 |
|---|---|---|
vecN.add(out, a, b) |
向量加法:out = a + b |
计算坐标偏移:vec3.add(out, currentPos, offset) |
vecN.sub(out, a, b) |
向量减法:out = a - b |
计算两点方向向量:vec3.sub(out, targetPos, currentPos) |
vecN.mul(out, a, b) |
分量乘法:out[i] = a[i] * b[i] |
坐标缩放:vec3.mul(out, pos, vec3.fromValues(2,2,2))(放大2倍) |
vecN.scale(out, a, s) |
标量乘法:out = a * s |
地理坐标转换为投影坐标:vec3.scale(out, lngLat, scale) |
vecN.scaleAndAdd(out, a, b, s) |
缩放并相加:out = a + b*s |
相机平滑移动:vec3.scaleAndAdd(out, cameraPos, moveDir, deltaTime) |
3. 向量属性与几何API
| API名称 | 作用 | GIS场景 |
|---|---|---|
vecN.length(a) |
计算向量长度(模):` | a |
vecN.distance(a, b) |
计算两点间欧氏距离:` | a-b |
vecN.dot(a, b) |
点积:`a·b = | a |
vecN.cross(out, a, b) |
叉积:仅vec3支持,out = a×b(垂直于a和b的向量) |
生成地形法向量、计算多边形朝向、判断点在直线哪一侧 |
vecN.normalize(out, a) |
归一化向量:`out = a/ | a |
vecN.angle(a, b) |
计算两向量夹角(弧度):`θ = arccos(a·b/( | a |
4. 插值与变换API
| API名称 | 作用 | GIS场景 |
|---|---|---|
vecN.lerp(out, a, b, t) |
线性插值:out = a + (b-a)*t,t∈[0,1] |
坐标平滑过渡、动画插值、轨迹生成 |
vecN.slerp(out, a, b, t) |
球面线性插值:仅vec3支持,平滑插值三维方向 |
无人机姿态过渡、相机朝向平滑旋转 |
vecN.transformMat4(out, a, m) |
向量与4x4矩阵相乘:out = m × a |
地理坐标→世界坐标/裁剪坐标转换、模型变换 |
vecN.transformMat3(out, a, m) |
向量与3x3矩阵相乘:out = m × a |
法向量变换、二维坐标旋转缩放 |
二、矩阵模块(mat2/mat3/mat4)
用于存储线性变换(平移、旋转、缩放、投影),mat4是WebGL/ WebGIS的核心(4x4矩阵支持齐次坐标变换)。
1. 创建与基础矩阵API
| API名称 | 作用 | 示例 |
|---|---|---|
matN.create() |
创建空的N×N矩阵,初始值为单位矩阵 | const modelMat = mat4.create(); |
matN.identity(out) |
将矩阵设置为单位矩阵(对角线为1,其余为0) | mat4.identity(modelMat); // 重置变换矩阵 |
matN.copy(out, a) |
复制矩阵a到out |
mat4.copy(outMat, modelMat); |
matN.fromTranslation(out, v) |
从平移向量创建4x4矩阵 | mat4.fromTranslation(out, vec3.fromValues(10,20,0)); // 平移(10,20,0) |
matN.fromRotation(out, rad, axis) |
从轴角创建4x4旋转矩阵 | mat4.fromRotation(out, Math.PI/2, vec3.fromValues(0,1,0)); // 绕Y轴转90° |
matN.fromScaling(out, v) |
从缩放向量创建4x4矩阵 | mat4.fromScaling(out, vec3.fromValues(2,2,2)); // 放大2倍 |
2. 矩阵变换API
| API名称 | 作用 | 注意事项 |
|---|---|---|
mat4.translate(out, a, v) |
平移变换:out = a × translate(v)(右乘,先应用平移) |
变换顺序:缩放→旋转→平移(矩阵乘法从右到左应用) |
mat4.rotate(out, a, rad, axis) |
旋转变换:out = a × rotate(rad, axis) |
旋转轴需归一化,否则会导致缩放错误 |
mat4.scale(out, a, v) |
缩放变换:out = a × scale(v) |
非均匀缩放会导致法向量方向错误,需用mat4.normalFromMat4修正 |
mat4.mul(out, a, b) |
矩阵乘法:out = a × b |
顺序至关重要:modelView = viewMat × modelMat(先模型变换,再视图变换) |
3. 投影与视图矩阵(WebGIS核心)
| API名称 | 作用 | GIS场景示例 |
|---|---|---|
mat4.ortho(out, left, right, bottom, top, near, far) |
正交投影矩阵 无透视效果,适合二维GIS(Mapbox) | const zoom = 10; const scale = Math.pow(2, zoom); mat4.ortho(out, -width/2scale, width/2 scale, -height/2scale, height/2scale, -1, 1); |
mat4.perspective(out, fovy, aspect, near, far) |
透视投影矩阵 有近大远小效果,适合三维GIS(Cesium) | mat4.perspective(out, Math.PI/3, window.innerWidth/window.innerHeight, 1, 1e7); // 60°视场角,10公里远裁剪面 |
mat4.lookAt(out, eye, center, up) |
视图矩阵 相机看向目标点,模拟人眼视角 | const eye = vec3.fromValues(116.4, 39.9, 1000); // 北京上空1000米const center = vec3.fromValues(116.4, 39.9, 0); // 北京地面mat4.lookAt(out, eye, center, vec3.fromValues(0,1,0)); // Y轴为上方向 |
4. 高级矩阵运算API
| API名称 | 作用 | GIS场景 |
|---|---|---|
mat4.invert(out, a) |
求逆矩阵:out = a⁻¹ |
世界坐标→相机坐标转换、反向变换 |
mat4.transpose(out, a) |
转置矩阵:out[i][j] = a[j][i] |
法向量矩阵计算、矩阵格式转换 |
mat4.normalFromMat4(out, a) |
法向量矩阵:out = (a⁻¹)ᵀ(逆矩阵的转置) |
模型缩放时修正法向量方向,避免光照错误 |
mat4.determinant(a) |
计算矩阵行列式:判断矩阵是否可逆 | 检测变换矩阵是否合法(行列式为0则不可逆) |
三、四元数模块(quat)
用于高效表示三维旋转,避免欧拉角的万向锁问题,旋转组合运算比矩阵快2-3倍,适合无人机姿态、三维模型旋转等WebGIS场景。
1. 创建与初始化API
| API名称 | 作用 | 示例 |
|---|---|---|
quat.create() |
创建空的四元数,初始值为[0,0,0,1](无旋转) |
const rotQuat = quat.create(); |
quat.fromEuler(out, x, y, z) |
从欧拉角(弧度)创建四元数 x/y/z分别为绕X/Y/Z轴的旋转角度 | quat.fromEuler(out, 0, Math.PI/2, 0); // 绕Y轴转90° |
quat.fromAxisAngle(out, axis, rad) |
从轴角创建四元数 绕axis轴旋转rad弧度 |
quat.fromAxisAngle(out, vec3.fromValues(0,1,0), Math.PI/2); // 同上方示例 |
quat.copy(out, a) |
复制四元数a到out |
quat.copy(outQuat, rotQuat); |
2. 旋转运算API
| API名称 | 作用 | GIS场景 |
|---|---|---|
quat.mul(out, a, b) |
四元数乘法:out = a × b(组合两个旋转,先应用b,再应用a) |
无人机姿态组合(先俯仰,再偏航) |
quat.invert(out, a) |
逆四元数:out = a⁻¹(反向旋转) |
无人机姿态回滚、反向旋转模型 |
quat.normalize(out, a) |
归一化四元数:避免数值误差导致旋转错误 | 长时间旋转后修正四元数精度 |
3. 转换与插值API
| API名称 | 作用 | GIS场景 |
|---|---|---|
quat.toMat4(out, q) |
将四元数转换为4x4旋转矩阵 用于WebGL模型变换 | quat.toMat4(modelMat, rotQuat); // 旋转矩阵应用到模型 |
quat.lerp(out, a, b, t) |
线性插值:短距离旋转平滑过渡 | 无人机小角度姿态调整 |
quat.slerp(out, a, b, t) |
球面线性插值:长距离旋转平滑过渡 无方向突变 | 无人机大角度转向、相机朝向平滑切换 |
quat.getAxisAngle(outAxis, outRad, q) |
从四元数提取轴角 得到旋转轴和旋转角度 | 调试旋转参数、显示无人机姿态信息 |
🚀 WebGIS专属优化实践
1. 性能优化
-
复用目标数组 :始终复用
out参数,避免频繁创建新Float32Arrayjavascript// 推荐写法 const out = vec3.create(); vec3.add(out, pos1, pos2); vec3.normalize(out, out); // 不推荐写法(创建2个临时数组) const temp = vec3.add(vec3.create(), pos1, pos2); const result = vec3.normalize(vec3.create(), temp); -
预计算静态矩阵:投影矩阵、视图矩阵等静态数据预计算并缓存,避免每一帧重复计算
-
避免不必要的归一化:仅在向量方向变化时归一化,静态方向向量一次归一化即可
2. GIS场景最佳实践
-
坐标转换流水线 :地理坐标→世界坐标→裁剪坐标
javascriptconst lngLat = vec3.fromValues(116.4, 39.9, 0); const worldPos = vec3.create(); vec3.transformMat4(worldPos, lngLat, modelMat); // 地理→世界 vec3.transformMat4(clipPos, worldPos, viewProjMat); // 世界→裁剪 -
地形法向量计算 :
javascriptconst v1 = vec3.create(); const v2 = vec3.create(); vec3.sub(v1, pos2, pos1); vec3.sub(v2, pos3, pos1); vec3.cross(normal, v1, v2); // 生成法向量 vec3.normalize(normal, normal); -
无人机姿态控制 :
javascriptconst pitch = quat.create(); const yaw = quat.create(); quat.fromEuler(pitch, Math.PI/6, 0, 0); // 俯仰30° quat.fromEuler(yaw, 0, Math.PI/2, 0); // 偏航90° const finalRot = quat.create(); quat.mul(finalRot, yaw, pitch); // 先俯仰,再偏航 quat.toMat4(modelMat, finalRot);
📚 快速参考表
| 模块 | 核心用途 | 关键API |
|---|---|---|
| vec3 | 地理坐标、法向量、方向向量 | fromValues、dot、cross、normalize、transformMat4 |
| mat4 | 投影、视图、模型变换矩阵 | ortho、perspective、lookAt、mul、invert、normalFromMat4 |
| quat | 三维旋转、姿态控制 | fromEuler、toMat4、mul、slerp |