如何在WebGL中输出大于1的片段值

时间:2014-07-20 21:51:36

标签: glsl webgl

假设我正在渲染2个样本,这些样本将合并为一个图像。第一个样本包含超出可显示像素范围的值(在这种情况下,大于1)。但是当被第二个样本减去时,它确实落在了范围内。

在合并之前,我将样本存储在帧缓冲纹理中。

我希望能够存储大于1的值,但这些值被钳制为1. GLSL片段着色器是否可以输出这样的值?纹理可以存储它们吗?如果没有,我还能怎样存储它们?

根据this page,有可能:

  

渲染到屏幕要求输出具有可显示格式,而在多通道管道中并非总是这样。有时,传递产生的纹理需要具有浮点格式,不能直接转换为颜色

但根据规范,纹理浮点数被限制在[0,1]范围内。

3 个答案:

答案 0 :(得分:2)

片段着色器可以输出[0.0,1.0]范围之外的值,但前提是写入值的缓冲区格式支持该范围之外的值。启用此功能所需的是渲染目标(渲染缓冲区或附加到FBO的纹理),用于存储浮点值。

OpenGL ES 2.0及更低版本不需要支持浮点格式纹理。 OpenGL ES 3.0及更高版本。例如,在ES 3.0中,您可以将GL_RGBA16F用于具有16位浮点(又称半浮点)组件的RGBA纹理,并将GL_RGBA32F用于32位浮点组件。但是,ES 3.0和3.1仍然不需要支持将这些格式用作渲染目标,这就是这个用例所需要的。

ES 2.0实现可以通过支持OES_texture_half_float扩展来支持OES_texture_float和浮动纹理,从而提供半浮点纹理。为了支持渲染半浮动纹理,它们还需要EXT_color_buffer_half_floatEXT_color_buffer_float定义渲染浮动纹理,但指定基于ES 3.0。

总结:

  • ES 2.0及更高版本可以通过支持OES_texture_half_float和EXT_color_buffer_half_float扩展来支持渲染到16位浮点纹理。
  • ES 3.0及更高版本可以通过支持OES_texture_float和EXT_color_buffer_float扩展来支持渲染到32位浮点纹理。

如果您想使用这些功能,则必须在设备上测试这些扩展程序的存在。

答案 1 :(得分:2)

最简单的方法是使用浮点纹理。

var gl = someCanvasElement.getContext("experimental-webgl");
var ext = gl.getExtension("OES_texture_float");
if (!ext) {
    alert("no OES_texture_float");
    return;
}

现在您可以使用浮点纹理创建和渲染。接下来要做的是看看你是否可以渲染到浮点纹理。

var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.FLOAT, null);
gl.texParameteri(gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(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) {
  alert("can not render to floating point textures");
  return;
}

使用OES_texture_float

时,浮动不会被限制

如果设备不支持渲染到浮点纹理,那么您必须以其他方式对结果进行编码,例如gil建议

WebGL2

注意:在WebGL2中,浮点纹理始终可用。另一方面,如果要过滤浮点纹理,仍需检查并启用OES_texture_float_linear。同样在WebGL2中,您需要启用EXT_color_float_buffer渲染到浮点纹理(并且您仍然需要调用gl.checkFramebufferStatus,因为它取决于驱动器支持哪些附件组合。

答案 2 :(得分:0)

这里的关键思想是使用[0,1]范围内的2或4个固定点8位通道(颜色通道)在一些不受限制的范围内编码浮点数。此方法是通用的,适用于WebGL或任何其他GL系统。

假设您从浮点值开始:

float value;

假设您的机器支持mediump(16位浮点数),您可以使用编码值 2个8位通道:

float myNormalize(float val)
    {
    float min = -1.0;
    float max = 1.0;
    float norm = (val - min) / (max - min);
    return norm;
    }


vec2 encode_float_as_2bytes(float a)
    {
    a = myNormalize(a);
    vec2 enc = vec2(1.0, 256.0);
    enc *= a;
    enc = fract(enc);
    enc.x -= enc.y * (1.0 / 256.0);
    return enc;
    }

这里encode_float_as_2bytes(float a)接受要编码的值。首先使用一些边界值将值标准化为[0,1](在我的示例中,我的浮点数可以取[-1,1]中的值。标准化后,使用vec2对值进行编码。 现在,您可以将编码值写入颜色缓冲区:

float a = compute_something(...);
gl_FragColor.xy = encode_float_as_2bytes(a);

现在,当读取编码值(通过其他着色器或使用glReadPixels())时,您可以解码编码的float并获取值:

float denormalize(float val)
    {
    float min = -1.0;
    float max = 1.0;
    float den = val * (max - min) + min;
    return den;
    }


float decode_2_bytes(vec2 a)
    {
    float ret;
    ret = a.x * 1.0 + a.y * 1.0/256.0;
    ret = denormalize(ret);
    return ret;
    }

注意非规范化值必须与规范化值匹配(在此示例中为-1,1。

您可以在此处找到有关浮动编码的更多信息:http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/

相关问题