Found a way to access big arrays in shaders

I found a nice way to access big arrays in shaders with the texture from ofImage (nothing new - just want to share it, because it took me some time to figure it out):
Allocate the image:
image.allocate(data.size(), 1, OF_IMAGE_COLOR_ALPHA);

Load the data into the image:

	for (int i = 0; i < data.size(); i++) {
		image.setColor(i, 0, ofColor(data[i] / 256 / 256 / 256, data[i] / 256 / 256, data[i] / 256, data[i]));
	}
	image.update();

Send it to the shader:
shaderRandom.setUniformTexture("Tex1", image.getTexture(), 0);

And access it in the shader (i is the pixel on the x-axis of the texture):

	vec2 texcoord = vec2(float(i) + 0.5, 0.5) / vec2(textureSize.x, 1.);
	vec4 pixelData = floor(texture(Tex1, texcoord) * 256.);
	float pixelValue = pixelData.r * 256. * 256. * 256. + pixelData.g * 256. * 256. + pixelData.b * 256. + pixelData.a;

This way it is possible to access a lot of values with the range of 4294967296 (with OF_IMAGE_COLOR_ALPHA) for each pixel. If less is needed an OF_IMAGE_COLOR or OF_IMAGE_GRAYSCALE is fine too. Or access three or four seperate channels of data with the range of 256.

Here the whole shader: ofEmscriptenExamples/random.frag at main · Jonathhhan/ofEmscriptenExamples · GitHub

1 Like

Hey @Jona, nice post about this! Just curious if you have ever tried using ofBufferObject to do the same thing. The /gl/textureBufferInstancedExample uses this class to get data into the vertex shader, which uses texelFetch() to sample a GL_RGBA32F texture.

1 Like

thx for posting this!

I use this image as data technique alot, especially when doing webgl work – I wonder if you can use float pixels ofFloatPixels – vs the conversion from float to R/G/B (which seems useful – but also probably not great for very small values as floats are non linearly spaced)

1 Like

Hi @TimChi, thanks. I was not aware that I can do that with ofBufferObject too, will definitely take a look into the example.

@zach I guess the problem with that is, in my case, that I use GL ES which does not support float textures (it should be possible to enable an extension, but I failed with that).

I was thinking after I posted that this could be an issue, and didn’t know that GLES had this limitation. So does using texture() result in a “blended value” for a sample with its neighbors? I always thought that it does, but I could very well be wrong. Or do you seem to get the “true value” for each sample? I think the example uses texelFetch() to sample the “true value” (unblended?) in the texture, but I’ve always wondered about this.

I like how you’ve done this. And a huge benefit is that it should work for both GL and GLES. So you don’t have to rewrite as much to port to iOS, an RPi, or use Emscripten.

@TimChi I seem to get the true value after I did this flooring:
vec4 pixelData = floor(texture(Tex1, texcoord) * 256.);

1 Like

Actually float textures work (at least with Emscripten) with a very small change, made a PR regarding that…

2 Likes