3

I wrote some WebGL code that is based on floating point textures. But while testing it on a few more devices I found that support for the OES_texture_float extension isn't as widespread as I had thought. So I'm looking for a fallback.

I have currently a luminance floating point texture with values between -1.0 and 1.0. I'd like to encode this data in a texture format that is available in WebGL without any extensions, so probably a simple RGBA unsigned byte texture.

I'm a bit worried about the potential performance overhead because the cases where this fallback is needed are older smartphones or tablets which already have much weaker GPUs than a modern desktop computer.

How can I emulate floating point textures on a device that doesn't support them in WebGL?

genpfault
  • 51,148
  • 11
  • 85
  • 139
John Doe
  • 131
  • 1
  • 2
  • 2
    Possible duplicate of [How do you pack one 32bit int Into 4, 8bit ints in glsl / webgl?](http://stackoverflow.com/questions/18453302/how-do-you-pack-one-32bit-int-into-4-8bit-ints-in-glsl-webgl) – LJᛃ Jan 23 '16 at 14:47
  • It's doable, but a lot of confusion around it caused by the limited GLSL 1.00 standard which preprocesses float literals making it look like these don't work. Paying a careful attention, one finds a path to implement precise bit-by-bit conversion. – Brian Cannard May 08 '20 at 08:05

2 Answers2

4

If you know your range is -1 to +1 the simplest way is to just to convert that to some integer range and then convert back. Using the code from this answer which packs a value that goes from 0 to 1 into a 32bit color

const vec4 bitSh = vec4(256. * 256. * 256., 256. * 256., 256., 1.);
const vec4 bitMsk = vec4(0.,vec3(1./256.0));
const vec4 bitShifts = vec4(1.) / bitSh;

vec4 pack (float value) {
    vec4 comp = fract(value * bitSh);
    comp -= comp.xxyz * bitMsk;
    return comp;
}

float unpack (vec4 color) {
    return dot(color , bitShifts);
}

Then

const float rangeMin = -1.;
const float rangeMax = -1.;

vec4 convertFromRangeToColor(float value) {
   float zeroToOne = (value - rangeMin) / (rangeMax - rangeMin);
   return pack(value);
}

float convertFromColorToRange(vec4 color) {
   float zeroToOne = unpack(color);
   return rangeMin + zeroToOne * (rangeMax - rangeMin);
}
Community
  • 1
  • 1
gman
  • 100,619
  • 31
  • 269
  • 393
  • 1
    This doesn't work with linear filtering or any post-process filtering (eg. blur) – skrat Jan 14 '19 at 17:49
  • [Here's another solution for actual float numbers](https://stackoverflow.com/a/63830492/128511) – gman Sep 11 '20 at 12:44
1

This should be a good starting point: http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/

It's intended for encoding to 0.0 to 1.0, but should be straightforward to remap to your required range.

Columbo
  • 6,648
  • 4
  • 19
  • 30