GPU友好矩阵(坐标精度优化)
背景:大坐标情况下,实例化模型抖动问题处理:
背景:为什么 instancedMesh + 大坐标会抖?
你应该已经踩过这个坑了 👇
-
world 坐标:
(100000.123456, 0, 0) -
GPU 用的是 32-bit float
-
float 在 10⁵ 量级时:
-
最小可区分单位 ≈ 0.01 ~ 0.02
-
-
结果就是:
-
摄像机动一点
-
MVP 矩阵每帧算出来的结果不稳定
-
顶点在像素级来回跳 → 抖动
-
instancedMesh 更惨,因为:
-
instanceMatrix 直接进 shader
-
没有 per-object 的“局部坐标保护”
一句话先给结论
optimizeMatrixPrecision(worldMatrix)
👉 通过“人为降低世界矩阵中 position 的精度”,减少大坐标传入 GPU 后产生的浮点误差,从而缓解 instancedMesh / 大场景下的抖动问题。
它不是让精度更高,而是:
让 CPU 和 GPU 在“同一套低精度规则下工作”
GPU友好矩阵处理:
optimizeMatrixPrecision(worldMatrix) {
// 1. 提取位置分量
worldMatrix.decompose(pos, quat, scale);
// 2. 判断是否为大坐标
if (Math.abs(pos.x) > 10000 || ...) {
// 3. 舍入到固定精度
pos.x = Math.round(pos.x / 0.001) * 0.001;
}
// 4. 重新组合矩阵
return compose(pos, quat, scale);
}
2️⃣ 判断是否为「大坐标」
为什么是 10000?
这是一个经验阈值:
| 坐标量级 | float 精度 |
|---|---|
| 1 ~ 100 | 非常精确 |
| 1000 | 开始丢小数 |
| 10000 | 明显抖动 |
| 100000 | 灾难 |
👉 超过这个值,再保留很多小数 毫无意义
3️⃣ 舍入到固定精度(关键步骤)
这一步非常重要,你要从“反直觉”理解它:
❌ 不是为了提高精度
✅ 是为了 “稳定精度”
举个非常直观的例子
原始 position(每帧略有差异)
GPU float 实际能表示的可能是:
👉 每帧映射到不同 float → 抖
经过你这一步“量化”之后
👉 CPU 先统一规则
👉 GPU 每帧拿到的是同一个 float
这个 0.001 是什么?
这是你在定义:
“我允许这个世界里最小的空间单位是多少”
-
0.001 → 1 毫米
-
0.01 → 1 厘米(更稳)
-
0.1 → 10 厘米(超稳)
📌 越粗糙 → 越稳定
这个 API 实际上解决了什么?
✅ 能解决的
-
instancedMesh 在大坐标下:
-
顶点抖动
-
贴图 jitter
-
线条闪烁
-
-
摄像机轻微移动时模型晃动
-
instanceMatrix 每帧浮点不一致
具体实例:
/**
* 对矩阵进行大坐标精度优化
* 通过固定精度舍入来减少 Float32 精度损失
* @param {THREE.Matrix4} worldMatrix - 世界坐标矩阵
* @returns {THREE.Matrix4} 精度优化后的矩阵
*/
optimizeMatrixPrecision(worldMatrix) {
const pos = new THREE.Vector3();
const quat = new THREE.Quaternion();
const scale = new THREE.Vector3();
worldMatrix.decompose(pos, quat, scale);
// 只对大坐标进行精度舍入
const needsPrecisionOpt =
Math.abs(pos.x) > this.precisionScale ||
Math.abs(pos.y) > this.precisionScale ||
Math.abs(pos.z) > this.precisionScale;
if (needsPrecisionOpt) {
// 舍入到固定精度,避免累积误差
pos.x = Math.round(pos.x / this.precisionStep) * this.precisionStep;
pos.y = Math.round(pos.y / this.precisionStep) * this.precisionStep;
pos.z = Math.round(pos.z / this.precisionStep) * this.precisionStep;
}
const optimizedMatrix = new THREE.Matrix4();
optimizedMatrix.compose(pos, quat, scale);
return optimizedMatrix;
}

浙公网安备 33010602011771号