WebGL iOS renders floating point texture

I am trying to get a floating point texture rendering working in WebGL on iOS Safari (not in the native application). I managed to get iOS to read the manually created floating point texture (for example, from JavaScript), but when I create a floating point framebuffer and use the GPU to render into it, it does not work.

I highlighted a problem for code that displays a floating-point texture, which is then passed to another shader to be displayed. Here is the result applied to the cube:

rtt.png

Rendering to a texture draws a green square, half the size of the texture, which is then applied to each side of the cube.

All this works fine both on the desktop and on iOS WebGL, if the type of texture on which the green square is displayed is the standard type of unsigned byte. However, changing the type of the floating point leads to the failure of rendering the texture on iOS devices (while continuing to work in desktop browsers). The texture is empty, as if nothing had been done for her.

I created an example project here to demonstrate the problem: https://github.com/felixpalmer/render-2-texture

Changing the accuracy of shaders using the THREE.Renderer.precision parameter THREE.Renderer.precision not matter

+7
javascript ios opengl-es webgl
source share
1 answer

As far as I know, not a single iOS device supports floating-point texture rendering (as well as most mobile devices currently 3/2015)

My understanding of the WebGL specification is

OES_texture_float : Allows you to create and read from 32-bit floating textures, but floating point rendering is device dependent.

OES_texture_float_linear : Allows linear filtering of floating point textures. If this does not exist and OES_texture_float does, you can use gl.NEAREST for floating point textures.

OES_texture_half_float and OES_texture_half_float_linear are the same as above, except for the half float texture.

The traditional way to view floating point texture in WebGL, assuming OES_texture_float exists, is to create a framebuffer, attach a floating point texture to it, and then call gl.checkFramebufferStatus . If it returns gl.FRAMEBUFFER_COMPLETE , then you can, if not, then you cannot. Note. This method should work regardless of the next paragraph.

The specification has been updated so you can also check out WebGL extensions to see if floating point texture can be rendered. It is assumed that the WEBGL_color_buffer_float extension tells you that you can display floating point textures. The EXT_color_buffer_half_float extension EXT_color_buffer_half_float same for a half-float texture. I don't know a browser that actually shows these extensions, although they support floating point rendering if the hardware supports it.

For example, my 2012 Retina MBP in Chrome reports 41

 gl = document.createElement("canvas").getContext("webgl").getSupportedExtensions() ["ANGLE_instanced_arrays", "EXT_blend_minmax", "EXT_frag_depth", "EXT_shader_texture_lod", "EXT_sRGB", "EXT_texture_filter_anisotropic", "WEBKIT_EXT_texture_filter_anisotropic", "OES_element_index_uint", "OES_standard_derivatives", "OES_texture_float", "OES_texture_float_linear", "OES_texture_half_float", "OES_texture_half_float_linear", "OES_vertex_array_object", "WEBGL_compressed_texture_s3tc", "WEBKIT_WEBGL_compressed_texture_s3tc", "WEBGL_debug_renderer_info", "WEBGL_debug_shaders", "WEBGL_depth_texture", "WEBKIT_WEBGL_depth_texture", "WEBGL_lose_context", "WEBKIT_WEBGL_lose_context"] 

Firefox Reports 36

 gl = document.createElement("canvas").getContext("webgl").getSupportedExtensions().join("\n") "ANGLE_instanced_arrays EXT_blend_minmax EXT_frag_depth EXT_sRGB EXT_texture_filter_anisotropic OES_element_index_uint OES_standard_derivatives OES_texture_float OES_texture_float_linear OES_texture_half_float OES_texture_half_float_linear OES_vertex_array_object WEBGL_compressed_texture_s3tc WEBGL_depth_texture WEBGL_draw_buffers WEBGL_lose_context MOZ_WEBGL_lose_context MOZ_WEBGL_compressed_texture_s3tc MOZ_WEBGL_depth_texture" 

Browser vendors are busy implementing WebGL 2.0 and there is no pressure to use the gl.checkFramebufferStatus method to spend time creating other extension strings.

Apparently, some iOS devices support EXT_color_buffer_half_float , so you can try creating half of the floating texture, attach it to the framebuffer and check its status, and then see if this works.

Here is a sample for checking support. By running it on iPadAir2 and my iPhone5, I get

 can make floating point textures can linear filter floating point textures can make half floating point textures can linear filter floating point textures can **NOT** render to FLOAT texture successfully rendered to HALF_FLOAT_OES texture 

as we expected.

 "use strict"; function log(msg) { var div = document.createElement("div"); div.appendChild(document.createTextNode(msg)); document.body.appendChild(div); } function glEnum(gl, v) { for (var key in gl) { if (gl[key] === v) { return key; } } return "0x" + v.toString(16); } window.onload = function() { // Get A WebGL context var canvas = document.getElementById("c"); var gl = canvas.getContext("webgl"); if (!gl) { return; } function getExt(name, msg) { var ext = gl.getExtension(name); log((ext ? "can " : "can **NOT** ") + msg); return ext; } var testFloat = getExt("OES_texture_float", "make floating point textures"); getExt("OES_texture_float_linear", "linear filter floating point textures"); var testHalfFloat = getExt("OES_texture_half_float", "make half floating point textures"); getExt("OES_texture_half_float_linear", "linear filter half floating point textures"); gl.HALF_FLOAT_OES = 0x8D61; // setup GLSL program var program = webglUtils.createProgramFromScripts(gl, ["2d-vertex-shader", "2d-fragment-shader"]); gl.useProgram(program); // look up where the vertex data needs to go. var positionLocation = gl.getAttribLocation(program, "a_position"); var colorLoc = gl.getUniformLocation(program, "u_color"); // provide texture coordinates for the rectangle. var positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0]), gl.STATIC_DRAW); gl.enableVertexAttribArray(positionLocation); gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); var whiteTex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, whiteTex); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255, 255, 255, 255])); function test(format) { var tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, tex); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, format, null); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); var fb = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, fb); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0); var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER); if (status !== gl.FRAMEBUFFER_COMPLETE) { log("can **NOT** render to " + glEnum(gl, format) + " texture"); return; } // Draw the rectangle. gl.bindTexture(gl.TEXTURE_2D, whiteTex); gl.uniform4fv(colorLoc, [0, 10, 20, 1]); gl.drawArrays(gl.TRIANGLES, 0, 6); gl.bindTexture(gl.TEXTURE_2D, tex); gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.clearColor(1, 0, 0, 1); gl.clear(gl.COLOR_BUFFER_BIT); gl.uniform4fv(colorLoc, [0, 1/10, 1/20, 1]); gl.drawArrays(gl.TRIANGLES, 0, 6); var pixel = new Uint8Array(4); gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel); if (pixel[0] !== 0 || pixel[1] < 248 || pixel[2] < 248 || pixel[3] < 254) { log("FAIL!!!: Was not able to actually render to " + glEnum(gl, format) + " texture"); } else { log("succesfully rendered to " + glEnum(gl, format) + " texture"); } } if (testFloat) { test(gl.FLOAT); } if (testHalfFloat) { test(gl.HALF_FLOAT_OES); } } 
 canvas { border: 1px solid black; } 
 <script src="//webglfundamentals.org/webgl/resources/webgl-utils.js"></script> <canvas id="c" width="16" height="16"></canvas> <!-- vertex shader --> <script id="2d-vertex-shader" type="x-shader/x-vertex"> attribute vec4 a_position; void main() { gl_Position = a_position; } </script> <!-- fragment shader --> <script id="2d-fragment-shader" type="x-shader/x-fragment"> precision mediump float; uniform vec4 u_color; uniform sampler2D u_texture; void main() { gl_FragColor = texture2D(u_texture, vec2(0.5, 0.5)) * u_color; } </script> 
+13
source share

All Articles