对于经常出现的那个问题一个解决方案#
Data: 2025-12-02 23:52:40
绝对解决:
后续可以使用一下。
//---- 绝对防御版矩阵处理代码 ----------------------------------------------------
// 定义一个安全的默认矩阵 (单位矩阵)
const IDENTITY_MATRIX = new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]);
// 内部函数:绝对安全的矩阵上传
// 策略:无论发生什么,绝不 throw Error,遇到问题就用 Identity 顶替,保证画面不崩
function safeUniformMatrix(gl, location, mat) {
let data = IDENTITY_MATRIX;
if (mat) {
// 1. 尝试获取 float32 数组
let arr = null;
try {
// 如果 mat 本身就是 DOMMatrix,它有 toFloat32Array
if (mat.toFloat32Array) arr = mat.toFloat32Array();
// 如果 mat 已经是数组
else if (mat.length) arr = mat;
} catch (e) {
// console.warn("矩阵转换失败,使用默认值");
}
// 2. 只有当数组存在,且长度正确,且没有任何 NaN/Infinity 时,才使用它
// 注意:检查 !Number.isFinite 是核心,它能同时拦截 NaN 和 Infinity
if (arr && arr.length === 16 && !arr.some(v => !Number.isFinite(v))) {
data = arr;
} else {
// 可以在这里加一个计数器,只 log 前 5 次,避免刷屏
if (!W._nanWarned) {
console.warn("捕获到 NaN 矩阵,已自动修复为单位矩阵,防止崩溃。", object.n);
W._nanWarned = true; // 每一帧只报一次或者全局只报一次
}
}
}
// 3. 执行上传,此时 data 必然是干净的 Float32Array
gl.uniformMatrix4fv(location, false, data);
}
if (!just_compute) {
// 获取原始矩阵
let rawMatrix = W.next?.[object.n]?.M || W.next?.[object.n]?.m;
// 构建 safeMat (DOMMatrix 对象)
let safeMat;
try {
safeMat = new DOMMatrix(rawMatrix);
// 立即检查生成出来的矩阵是否含有 NaN (DOMMatrix 构造函数有时不报错但会生成 NaN)
if (isNaN(safeMat.m11) || isNaN(safeMat.m41)) {
throw new Error("NaN detected");
}
} catch (e) {
// 如果原始数据坏了,创建一个干净的单位矩阵,让物体哪怕位置不对,也不要报错
safeMat = new DOMMatrix();
// 甚至可以考虑把坏掉的数据重置,实现“自愈”
if(W.next[object.n]) W.next[object.n].m = safeMat;
}
// 上传模型矩阵 M
safeUniformMatrix(W.gl, W.uniformLocations.m, safeMat);
// 计算并上传逆矩阵 IM
let invMat;
try {
// invertSelf 可能会在矩阵不可逆(如缩放为0)时抛出错误或产生 NaN
// 这里我们克隆一个新的矩阵去求逆,避免污染 safeMat
invMat = DOMMatrix.fromFloat32Array(safeMat.toFloat32Array());
invMat.invertSelf();
} catch (e) {
invMat = new DOMMatrix(); // 求逆失败,回退到单位矩阵
}
safeUniformMatrix(W.gl, W.uniformLocations.im, invMat);
}
//------------------------------------------------------------------------------------