Uint8Array 我TM謝謝你不報錯哦

undefined發表於2022-04-12

為了節約記憶體, 對引數化資料的typedArray進行了判斷選擇

public static FillIndexArray(len: number) {
    let indexArr = len < 0x100 ? new Uint8Array(len) : (len < 0x10000 ? new Uint16Array(len) : new Uint32Array(len));
    for (let i = 0; i < len; ++i) {
        indexArr[i] = i;
    }
    return indexArr;
}

在進行合批操作時,合併所有的頂點、索引和Uv資料

// 合併index資料
for (let i = 0; i < this.Geometries.length; ++i) {
    index.set(geo.Indices.map(x => x + curPosition/3), curIndex);
    curIndex += geo.Indices.length;
}

OK, 這時候就出現了問題,反正就是繪製不對,很奇怪的形狀

在索引、頂點、法線中,我覺得只有索引出錯才能導致這種情況,所以追蹤分析。

解決

罪魁呢 就是Uint8Array,因為這小子啊,下邊越界不報錯,給我又迴圈一遍...
對於原理,我用幾句程式碼說明

 const a = new Uint8Array(10)
  const b = a.map(v => v)
  console.log(b) // 結果 [0, 0, 0, 0,....]

當相加改變數值大小,直到邊界

const a = new Uint8Array(10)
  const b = a.map(v => v+255)
  console.log(b) // 結果 [255, 255, 255, 255,....]

再次相加

const a = new Uint8Array(10)
  const b = a.map(v => v+256)
  console.log(b) // 結果 [0, 0, 0, 0,....]

原理就是當Uint8Array越界之後不會報錯,並且會在下一個邊界迴圈! 看MDN

解決方法就是加完後判斷下大小

// @ts-ignore
const max = geo.Indices.reduce((acc, val) => {
    const value = val + curPosition/3
    if(value >= acc) {
        acc = value;
    }
    return acc;
}, 0)

const mapCount = geo.Indices.length
const mapIndices = max < 0x100 ? new Uint8Array(mapCount) : (indexCount < 0x10000 ? new Uint16Array(mapCount) : new Uint32Array(mapCount));
for(let i =0; i < mapCount; ++i) {
    mapIndices[i] = geo.Indices[i]
}

index.set(mapIndices.map(x => x + curPosition/3), curIndex);

相關文章