JavaScript TypedArray типы смешивания - PullRequest
0 голосов
/ 11 мая 2018

Я пытаюсь использовать WebGL и хотел бы смешать несколько разных типов в один буфер байтов. Я понимаю, что TypedArrays служат для этой цели, но не ясно, могу ли я смешивать типы с ними (данные вершин OpenGL часто плавающие, смешиваются с байтами без знака или целыми числами).

В моем тесте я хочу упаковать 2 поплавка в UInt8Array, используя set(), но, похоже, просто поместите 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)

1 Ответ

0 голосов
/ 11 мая 2018

Вы можете смешивать типы, создавая разные представления в одном и том же буфере.

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);

Способ работы TypeArrays заключается в том, что есть нечто, называемое 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);

Или вы можете сделать более обычную вещь - создать ArrayBufferView определенного типа, и он создаст оба ArrayBufferView этого типа и создайте для него ArrayBuffer, если вы не передадите его в конструктор.Затем вы можете получить доступ к этому буферу из someArrayBufferView.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);

Поэтому, если вы хотите, например, смешать плавающие позиции и цвета Uint8 для WebGL, вы можете сделать что-то вроде

// 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;
  }
}
...