在WebGL中打包数据:Chrome中的float64 / int64Arrays

时间:2012-03-06 12:08:51

标签: webkit webgl

[编辑 - 几乎修复了一个问题,改变了问题以反映它]

我正在使用Chrome中的点云webGL项目,该项目一次显示数百万个点。

为了提高效率,我尝试将我的数据 - 6 xyz和rgb浮点数 - 打包成两个64位整数(xy& zrgb),并计划在着色器中解压缩它们。

我正在使用Chrome进行开发,而且即使使用Canary,webkit也不支持任何类型的64位阵列类型。另外,Firefox确实支持64位阵列,但我仍然遇到错误。

这一行出现了问题:

gl.bufferData(gl.ARRAY_BUFFER, new Float64Array(data.xy), gl.DYNAMIC_DRAW);

在Chrome中我得到的ArrayBufferView不是一个足够小的正整数,在FF中我得到'无效参数'。

所以我的问题是,有没有办法将64位数字发送到着色器,最好是使用Chrome,如果没有,在FF中?

另外,这样的包装数据是个好主意吗?有什么提示吗?!

谢谢,

约翰

1 个答案:

答案 0 :(得分:8)

重要的是要知道WebGL实际上并不关心您提供它的TypedArray格式。无论你给它什么,它都会将它视为不透明的二进制缓冲区。重要的是你如何设置vertexAttribPointer。这允许一些非常方便的来回移动数据的方法。例如:我经常从二进制文件中读取Uint8Array并将其作为缓冲区数据提供,但将其绑定为浮点数和整数。

TypedArrays还具有很好的作为其他数组类型视图的能力,这使得混合类型变得容易(只要你没有对齐问题)。在你的具体情况下,我建议做这样的事情:

var floatBuffer = new Float32Array(verts.length * 4);
var byteBuffer = new Uint8Array(floatBuffer); // View the floatBuffer as bytes

for(i = 0; i < verts.length; ++i) {
    floatBuffer[i * 4 + 0] = verts.x;
    floatBuffer[i * 4 + 1] = verts.y;
    floatBuffer[i * 4 + 2] = verts.z;

    // RGBA values expected as 0-255
    byteBuffer[i * 16 + 12] = verts.r;
    byteBuffer[i * 16 + 13] = verts.g;
    byteBuffer[i * 16 + 14] = verts.b;
    byteBuffer[i * 16 + 15] = verts.a;
}

var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, floatBuffer, gl.STATIC_DRAW);

这会将一个包含3个32位浮点数和1个32位颜色的紧凑顶点缓冲区上传到GPU。不像你提出的64位整数那么小,但GPU可能会更好地使用它。绑定它以便稍后渲染时,你会这样做:

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.vertexAttribPointer(attributes.aPosition, 3, gl.FLOAT, false, 16, 0);
gl.vertexAttribPointer(attributes.aColor, 4, gl.UNSIGNED_BYTE, false, 16, 12);

相应的着色器代码如下所示:

attribute vec3 aPosition;
attribute vec4 aColor;

void main() {
    // Manipulate the position and color as needed
}

通过这种方式,您可以使用GPU喜欢使用的交错数组,并且只需要跟踪单个缓冲区(奖励!),而且您不会为每个颜色组件使用完整浮动浪费空间。如果你真的想要变小,你可以使用短裤而不是花车作为位置,但我过去的经验表明桌面GPU在使用短属性时并不是非常快。

希望这有帮助!