我已经将问题隔离到渲染到浮点纹理的代码,然后将其传递给另一个要显示的着色器.以下是应用于多维数据集的结果:
纹理渲染绘制绿色正方形,纹理的一半大小,然后应用于立方体的每一侧.
只要绿色方块呈现的纹理类型是标准的无符号字节类型,这在桌面和iOS WebGL上都可以正常工作.但是,将类型更改为浮点会导致iOS设备上的渲染纹理失败(同时继续在桌面浏览器上工作).纹理是空的,就好像没有渲染任何东西一样.
我在这里创建了一个示例项目来演示该问题:https://github.com/felixpalmer/render-2-texture
使用THREE.Renderer.precision设置更改着色器的精度并没有什么区别
解决方法
我对WebGL规范的理解是
OES_texture_float:允许您创建和读取32位浮点纹理,但渲染到浮点是依赖于设备的.
OES_texture_float_linear:允许线性滤镜浮点纹理.如果这不存在且OES_texture_float那么你只能使用gl.NEAREST来表示浮点纹理.
除半浮点纹理外,OES_texture_half_float和OES_texture_half_float_linear与上面相同.
假设存在OES_texture_float,在WebGL中渲染到浮点纹理的传统方法是创建帧缓冲区,为其附加浮点纹理,然后调用gl.checkFramebufferStatus.如果它返回gl.FRAMEBUFFER_COMPLETE那么你可以,如果不是那么你就不能.注意:无论下一段如何,此方法都应该有效.
规范已更新,因此您还可以检查WebGL扩展,以确定是否可以渲染到浮点纹理.扩展WEBGL_color_buffer_float应该告诉你可以渲染到浮点纹理.半浮点纹理的扩展名EXT_color_buffer_half_float是相同的.我知道没有实际显示这些扩展的浏览器,但如果硬件支持它们,它们支持浮点渲染.
例如我在Chrome 41上的2012 Retina MBP报告
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 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"
浏览器供应商正在忙于实现WebGL 2.0,并且在gl.checkFramebufferStatus方法工作的情况下,没有压力花时间显示其他扩展字符串.
显然有些iOS设备支持EXT_color_buffer_half_float,因此您可以尝试创建半浮动纹理,将其附加到帧缓冲区并检查其状态,然后查看是否有效.
这是检查支持的示例.我在我的iPadAir2和我的iPhone5s上运行它
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
这正是我们的预期.
"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]),gl.STATIC_DRAW); gl.enableVertexAttribArray(positionLocation); gl.vertexAttribPointer(positionLocation,2,gl.FLOAT,false,0); var whiteTex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D,whiteTex); gl.texImage2D(gl.TEXTURE_2D,gl.RGBA,1,gl.UNSIGNED_BYTE,new Uint8Array([255,255,255])); function test(format) { var tex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D,tex); gl.texImage2D(gl.TEXTURE_2D,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,6); gl.bindTexture(gl.TEXTURE_2D,tex); gl.bindFramebuffer(gl.FRAMEBUFFER,null); gl.clearColor(1,1); gl.clear(gl.COLOR_BUFFER_BIT); gl.uniform4fv(colorLoc,1/10,1/20,6); var pixel = new Uint8Array(4); gl.readPixels(0,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>