JavaScript TypedArray 混合类型
JavaScript TypedArray mixing types
我正在尝试使用 WebGL,并希望将一些不同的类型混合到一个字节缓冲区中。我了解 TypedArrays 用于此目的,但不清楚我是否可以将类型与它们混合使用(OpenGL 顶点数据通常是与无符号字节或整数混合的浮点数)。
在我的测试中,我想使用 set()
将 2 个浮点数打包到 UInt8Array
中,但它似乎只是将 2 个浮点数放入 UInt8Array
的前 2 个元素中。我希望这当然会填充数组,因为我们有 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)
您可以通过在同一缓冲区上创建不同的视图来混合类型。
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);
因此,例如,如果您想为 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;
}
}
我正在尝试使用 WebGL,并希望将一些不同的类型混合到一个字节缓冲区中。我了解 TypedArrays 用于此目的,但不清楚我是否可以将类型与它们混合使用(OpenGL 顶点数据通常是与无符号字节或整数混合的浮点数)。
在我的测试中,我想使用 set()
将 2 个浮点数打包到 UInt8Array
中,但它似乎只是将 2 个浮点数放入 UInt8Array
的前 2 个元素中。我希望这当然会填充数组,因为我们有 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)
您可以通过在同一缓冲区上创建不同的视图来混合类型。
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);
因此,例如,如果您想为 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;
}
}