JavaScript TypedArray 混合类型

Gen*_*Ptr 2 javascript webgl typed-arrays

我正在尝试使用 WebGL,并希望将一些不同类型混合到一个字节缓冲区中。我知道 TypedArrays 可以达到这个目的,但不清楚我是否可以与它们混合类型(OpenGL 顶点数据通常是与无符号字节或整数混合的浮点数)。

在我的测试中,我想将 2 个浮点数打包到 using 中UInt8Arrayset()但它似乎只是将 2 个浮点数放入 的前 2 个元素中UInt8Array。当然,我希望它能填满数组,因为我们有 8 个字节的数据。

无论如何,有没有办法在 JavaScript 中实现这一点,或者我是否需要将所有顶点数据保留为浮点数?

src = new Float32Array(2); // 2 elements = 8 bytes
src[0] = 100;
src[1] = 200;

dest = new UInt8Array(8); // 8 elements = 8 bytes
dest.set(src, 0); // insert src at offset 0

dest = 100,200,0,0,0,0,0,0 (only the first 2 bytes are set)
Run Code Online (Sandbox Code Playgroud)

gma*_*man 7

您可以通过在同一缓冲区上创建不同的视图来混合类型。

const asFloats = new Float32Array(2);
// create a uint8 view to the same buffer as the float32array
const asBytes = new Uint8Array(asFloats.buffer);

console.log(asFloats);
asBytes[3] = 123;
console.log(asFloats);
Run Code Online (Sandbox Code Playgroud)

TypeArrays 真正工作的方式是有一个叫做 an 的东西ArrayBuffer,它有一定的字节长度。要查看字节,您需要一个字节ArrayBufferView,其中有各种类型Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array

您可以从头开始创建ArrayBuffer

const buffer = new ArrayBuffer(8);
const asFloats = new Float32Array(buffer);
asFloats[0] = 1.23;
asFloats[1] = 4.56;
console.log(asFloats);
Run Code Online (Sandbox Code Playgroud)

或者,您可以做更正常的事情,即创建ArrayBufferView特定类型的 ,如果您不将其传递给构造函数它将创建ArrayBufferView该类型的,并为其创建 。然后,您可以从上面第一个示例中所示的位置访问该缓冲区。ArrayBuffersomeArrayBufferView.buffer

您还可以为视图分配一个偏移量ArrayBuffer和一个长度,以使其小于ArrayBuffer。例子:

// make a 16byte ArrayBuffer and a Uint8Array (ArrayBufferView)
const asUint8 = new Uint8Array(16);

// make a 1 float long view in the same buffer
// that starts at byte 4 in that buffer
const byteOffset = 4;
const length = 1;  // 1 float32
const asFloat = new Float32Array(asUint8.buffer, byteOffset, length);

// show the buffer is all 0s
console.log(asUint8);

// set the float
asFloat[0] = 12345.6789

// show the buffer is affected at byte 4
console.log(asUint8);

// set a float out of range of its length
asFloat[1] = -12345.6789;  // this is effectively a no-op

// show the buffer is NOT affected at byte 8
console.log(asUint8);
Run Code Online (Sandbox Code Playgroud)

因此,如果你想为 WebGL 混合浮动位置和 Uint8 颜色,你可能会这样做

// we're going to have
// X,Y,Z,R,G,B,A, X,Y,Z,R,G,B,A, X,Y,Z,R,G,B,A, 
// where X,Y,Z are float32
// and R,G,B,A are uint8

const sizeOfVertex = 3 * 4 + 4 * 1;  // 3 float32s + 4 bytes
const numVerts = 3;
const asBytes = new Uint8Array(numVerts * sizeOfVertex);
const asFloats = new Float32Array(asBytes.buffer);

// set the positions and colors
const positions = [
  -1,  1, 0,
   0, -1, 0,
   1,  1, 0,
];
const colors = [
   255, 0, 0, 255,
   0, 255, 0, 255,
   0, 0, 255, 255,
];
{
  const numComponents = 3;
  const offset = 0;  // in float32s
  const stride = 4;  // in float32s
  copyToArray(positions, numComponents, offset, stride, asFloats);
}
{
  const numComponents = 4;
  const offset = 12;  // in bytes
  const stride = 16;  // in bytes
  copyToArray(colors, numComponents, offset, stride, asBytes);
}

console.log(asBytes);
console.log(asFloats);

function copyToArray(src, numComponents, offset, stride, dst) {
  const strideDiff = stride - numComponents;
  let srcNdx = 0;
  let dstNdx = offset;
  const numElements = src.length / numComponents;
  if (numElements % 1) {
    throw new Error("src does not have an even number of elements");
  }
  for (let elem = 0; elem < numElements; ++elem) {
    for(let component = 0; component < numComponents; ++component) {
      dst[dstNdx++] = src[srcNdx++];
    }
    dstNdx += strideDiff;
  }
}
Run Code Online (Sandbox Code Playgroud)