我已经将问题隔离到渲染到浮点纹理的代码,然后将其传递给另一个要显示的着色器.以下是应用于多维数据集的结果:
纹理渲染绘制绿色正方形,纹理的一半大小,然后应用于立方体的每一侧.
只要绿色方块呈现的纹理类型是标准的无符号字节类型,这在桌面和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>