Floating point 如何最好地打包2个纹理坐标以进行快速顶点缓冲区处理?(WebGL GPU浮动填料)

Floating point 如何最好地打包2个纹理坐标以进行快速顶点缓冲区处理?(WebGL GPU浮动填料),floating-point,glsl,webgl,shader,bit-manipulation,Floating Point,Glsl,Webgl,Shader,Bit Manipulation,我想知道,在以下情况下,smartes如何打包2个纹理坐标以便在顶点着色器中快速使用: 两个纹理坐标只能为1.0f或0.0f=>1位,每个就足够了 我必须将这两个坐标打包到一个GLByte(8位)属性变量中;但是,如果6位仍可用于其他用途,则最好是这样 我的问题是,我不太熟悉浮动的位布局,但我可以想象,只有0.0f中的1位需要翻转成1.0f,我不知道是哪一位;仅使用位运算,这应该是难以置信的快(顺便说一句:gpu在位运算方面也比CPU等算术运算快吗?) 在顶点着色器中是这样做的: uv =

我想知道,在以下情况下,smartes如何打包2个纹理坐标以便在顶点着色器中快速使用:

  • 两个纹理坐标只能为1.0f或0.0f=>1位,每个就足够了
  • 我必须将这两个坐标打包到一个GLByte(8位)属性变量中;但是,如果6位仍可用于其他用途,则最好是这样

我的问题是,我不太熟悉浮动的位布局,但我可以想象,只有0.0f中的1位需要翻转成1.0f,我不知道是哪一位;仅使用位运算,这应该是难以置信的快(顺便说一句:gpu在位运算方面也比CPU等算术运算快吗?)

在顶点着色器中是这样做的:

uv = fract(vertex.xy);
normal = fract(vertex.z);
gl_Position = mvp * vec4(floor(vertex), 1.0)
显然,顶点xyz在存储到VBO之前必须按最大纹理分辨率放大,在这种情况下,例如256x256:

vbo.push_back(vertex.mul_xyz_scalar(256.0).floor().add_xyz(uv.x, uv.y, normal));
所以,如果顶点.x是.00390625,它就变成了1。低于1/256的位置低于正常值(丢失,上面的楼层截断)。uv已假定在0-1范围内。如果你真的坚持,你只需要乘以2而不是256,那么除了0和1之外的任何东西都会丢失

一句警告的话。仅当内存带宽(许多顶点、简单着色器、通常非常复杂的静态网格)限制时,此技术才有效。否则,着色器中额外的floor()成本是不值得的,最好将uv和法线并排存储

最后,所有顶点都必须按如下方式放大256(如果使用不同的着色器而不使用压缩uv/n),或通过mvp矩阵缩小256(这通常不会产生额外的开销,除非直接在着色器中进行,而不使用现有矩阵)

忍者编辑:这是一个快速的通用函数,用于填充在浮动中的“字节”

/*
 * Packed with: (x*32768+y*128+z)/32768.0 where x and y are 0-255, z is 0-127.
 * This function returns x and y in 0-256, and z in 0-1 range, scale to 128 as needed.
 */
void unpack887(in float v, out float x, out float y, out float z)
{
  x = floor(v);
  float rem = (v - x) * 256.0;
  y = floor(rem);
  z = rem - y;
}

嗯,最快的操作是那些你不需要做的操作。由于您已经用WebGL标记了您的问题,我需要告诉您,它的GLSL ES不支持位运算符。真的吗?不可能在一个字节内同时打包两个纹理坐标?如果每个顶点需要32x2而不是1x8位,这将极大地增加所需的带宽。您可以打包它们,但需要通过着色器中的乘法和除法来解压它们。我怀疑这会比拥有一个更大的缓冲区快。好吧,减少缓冲区大小的主要动机是它包含一些静态数据(所有的几何图形)和一些高度动态的内容,每200ms左右更新一次。我也在考虑使用多个数组,然后我可以让几何位置和纹理坐标完全静止,只改变那些正方形的“纹理索引”。在这种情况下,我认为保持缓冲区分开将节省大量带宽来更新它们。另一种可能的解决方案是在gpu上执行所有计算,并在运行中计算texcoords,或者如果不可能,则将其渲染为纹理(例如RGBA_4_4_4_4_4_4_4),并在顶点着色器中执行纹理查找。顶点着色器中的纹理查找可能会非常慢,但根据缓冲区大小,它可能会在您的情况下提高性能。