javascript – WebGL iOS渲染到浮点纹理

我正在尝试渲染到iOS Safari上的WebGL中的浮点纹理(不是在本机应用程序中).我已经设法让iOS手动(例如从 JavaScript)读取创建的浮点纹理,但是当我创建浮点类型的帧缓冲并使用GPU渲染到它时,它不起作用.

我已经将问题隔离到渲染到浮点纹理的代码,然后将其传递给另一个要显示的着色器.以下是应用于多维数据集的结果:

纹理渲染绘制绿色正方形,纹理的一半大小,然后应用于立方体的每一侧.

只要绿色方块呈现的纹理类型是标准的无符号字节类型,这在桌面和iOS WebGL上都可以正常工作.但是,将类型更改为浮点会导致iOS设备上的渲染纹理失败(同时继续在桌面浏览器上工作).纹理是空的,就好像没有渲染任何东西一样.

我在这里创建了一个示例项目来演示该问题:https://github.com/felixpalmer/render-2-texture

使用THREE.Renderer.precision设置更改着色器的精度并没有什么区别

解决方法

据我所知,iOS设备不支持渲染浮点纹理(此时此时大多数移动设备也不支持)

我对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>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


kindeditor4.x代码高亮功能默认使用的是prettify插件,prettify是Google提供的一款源代码语法高亮着色器,它提供一种简单的形式来着色HTML页面上的程序代码,实现方式如下: 首先在编辑器里面插入javascript代码: 确定后会在编辑器插入这样的代码: <pre
这一篇我将介绍如何让kindeditor4.x整合SyntaxHighlighter代码高亮,因为SyntaxHighlighter的应用非常广泛,所以将kindeditor默认的prettify替换为SyntaxHighlighter代码高亮插件 上一篇“让kindeditor显示高亮代码”中已经
js如何实现弹出form提交表单?(图文+视频)
js怎么获取复选框选中的值
js如何实现倒计时跳转页面
如何用js控制图片放大缩小
JS怎么获取当前时间戳
JS如何判断对象是否为数组
JS怎么获取图片当前宽高
JS对象如何转为json格式字符串
JS怎么获取图片原始宽高
怎么在click事件中调用多个js函数
js如何往数组中添加新元素
js如何拆分字符串
JS怎么对数组内元素进行求和
JS如何判断屏幕大小
js怎么解析json数据
js如何实时获取浏览器窗口大小
原生JS实现别踩白块小游戏(五)
原生JS实现别踩白块小游戏(一)