THREE.js - 大型int作为Uniform

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了THREE.js - 大型int作为Uniform相关的知识,希望对你有一定的参考价值。

我想为Three.js编写一个片段着色器,它需要一个10000个整数的大数组。当我尝试在着色器的glsl代码中声明这样的数组时:

uniform int colorGrid[10000];

然后着色器渲染器抛出

ERROR: too many uniform

我还有哪些其他选择 - 如何将如此大的数据块传递给片段着色器?

答案

纹理是大型数组。在纹理中传递整数有点困难但并非不可能(对于WebGL2,见下文)。您需要在纹理的红色,绿色,蓝色和Alpha通道上拆分整数值,或者FLOAT纹理,它将为您提供最大为2 ^ 24的整数值

要将整数打包到纹理中,您可以执行类似这样的操作

// assumes unsigned ints
setPixelFromInt(pixels, width, x, y, intValue) {
   var r = (intValue >> 24) & 0xFF;
   var g = (intValue >> 16) & 0xFF;
   var b = (intValue >>  8) & 0xFF;
   var a = (intValue >>  0) & 0xFF;
   var offset = (y * width + x) * 4;
   pixels[offset + 0] = r;
   pixels[offset + 1] = g;
   pixels[offset + 2] = b;
   pixels[offset + 3] = a;
}

var width = 100;
var height = 100;
var pixels = new Uint8Array(width * height * 4);

...

要在着色器中恢复您的值,请执行以下操作吗?

uniform vec2 textureDimensions;
uniform sampler2D arrayTexture;

int getValueFromTexture(sampler2D arrayTexture, vec2 textureDimensions, int index) {
  float x = mod(float(index), textureDimensions.x);
  float y = floor(float(index) / textureDimensions.x);
  vec2 uv = (vec2(x, y) + .5) / textureDimensions;
  vec4 color = texture2D(arrayTexture, uv);
  return int(color.r * 256.0 * 256.0 * 256.0 +
             color.b * 256.0 * 256.0 +
             color.g * 256.0 +
             color.a);
}

务必将过滤设置为gl.NEAREST

注意:我实际上没有运行该代码,但它说明了这个想法

在WebGL2中,您可以使用8,16或32位的整数纹理,并且在着色器中有texelFetch函数,该函数将提取特定lod的特定纹素的值,而不进行过滤。还有一个textureSize功能,因此您不必手动传递制服中的纹理大小。

  const int lod = 0
  ivec2 textureDimensions = textureSize(arrayTexture, lod);
  int x = index % textureDimensions.x;
  int y = index / textureDimensions.x;
  ivec4 color = texelFetch(arrayTexture, ivec2(x,y), lod);

以上是关于THREE.js - 大型int作为Uniform的主要内容,如果未能解决你的问题,请参考以下文章

three.js 着色器材质之变量

three.js 给模型添加标注

three.js加载stl模型文件,怎么能让模型大小一致并居中

three.js 3d 模型作为超链接

动画 GIF 作为 THREE.js 中的纹理

THREE.js:2xMeshes 使用相同的向量作为位置