0

In WebGL, I am trying to create a texture with texels each consisting of 4 float values. Here I attempt to to create a simple texture with one vec4 in it.

var textureData = new Float32Array(4);

var texture = gl.createTexture();
gl.activeTexture( gl.TEXTURE0 );
gl.bindTexture(gl.TEXTURE_2D, texture);

gl.texImage2D(
          // target, level, internal format, width, height 
          gl.TEXTURE_2D, 0, gl.RGBA, 1, 1,
          // border, data format, data type, pixels
          0, gl.RGBA, gl.FLOAT, textureData
      );

My intent is to sample it in the shader using a sampler like so:

uniform sampler2D data;
...
vec4 retrieved = texture2D(data, vec2(0.0, 0.0));

However, I am getting an error during gl.texImage2D:

WebGL: INVALID_ENUM: texImage2D: invalid texture type
WebGL error INVALID_ENUM in texImage2D(TEXTURE_2D, 0, RGBA, 1, 1, 0, RGBA, FLOAT,
[object Float32Array])

Comparing the OpenGL ES spec and the OpenGL 3.3 spec for texImage2D, it seems like I am not allowed to use gl.FLOAT. In that case, how would I accomplish what I am trying to do?

newprogrammer
  • 2,514
  • 2
  • 28
  • 46
  • Do you need the precision of a float? Or the range? I haven't used WebGL, but I believe it's based on ES 2.0? With that feature set, I can't think of a good way to get more than 8-bit per component texture precision. I guess you could do something ugly like splitting the data into multiple textures. Say if you need 16-bit precision, you could store the top 8 bits in one texture, and the lower 8 bits in a second texture. Then sample both in the fragment shader, and combine the results back into the original value. ES 3.0 has float textures. – Reto Koradi Apr 17 '14 at 05:42
  • I'm trying to do particle simulation, I do need the range/precision of a float. – newprogrammer Apr 17 '14 at 05:58

2 Answers2

2

You can create a byte array from your float array. Each float should take 4bytes (32bit float). This array can be put into texture using a standard RGBA format with unsigned byte. This will create a texture where each texel contains a single 32bit floating number which seems to be exactly what you want.

The only problem is your floating value is split into 4 floating values when you retrieve it from texture in your fragment shader. So what you are looking for is most likely "how to convert vec4 into a single float".

You should note what you are trying to do with internal format being RGBA consisting of 32bit floats will not work as your texture will always be 32bit per texel so even somehow forcing floats into a texture should result into clamping or precision loss. And then even if the texture texel would consist of 4 RGBA 32bit floats your shader would most likely treat them as lowp using texture2D at some point.

Community
  • 1
  • 1
Matic Oblak
  • 16,318
  • 3
  • 24
  • 43
1

The solution to my problem is actually quite simple! I just needed to type

var float_texture_ext = gl.getExtension('OES_texture_float');

Now WebGL can use texture floats!

This MDN page tells us why:

Note: In WebGL, unlike in other GL APIs, extensions are only available if explicitly requested.

Community
  • 1
  • 1
newprogrammer
  • 2,514
  • 2
  • 28
  • 46