THREE.js - large int array as Uniform
I want to write a fragment shader for Three.js that needs a large array of 10,000 integers. When I try to declare an array like this in the glsl shader code:
uniform int colorGrid[10000];
then the shader renderer throws
ERROR: too many uniform
What other options do I have - how can I pass such a large chunk of data into the fragment shader?
Textures are large arrays. Passing integers in textures is a bit tricky, but not impossible (for WebGL2, see below). Either you need to split the integer values ββby the red, green, blue and alpha channels of the texture or FLOAT texture, which will give you integer values ββup to 2 ^ 24th
To pack an integer into a texture, you can do something like this
// 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);
...
To get your values ββback to the shader, do something like this?
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);
}
Make sure to set filtering to gl.NEAREST
Note. I haven't really run this code, but it illustrates the idea
In WebGL2, you can have whole textures of 8, 16 or 32 bits, and the shader has a function texelFetch
that will pull the value of a specific texel of a specific lot without filtering. There is also a function textureSize
so you don't have to manually pass the texture size on the form.
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);