假设我呈现的是两个样本,它们将合并成一个图像。第一个示例包含可显示像素范围以外的值(在这种情况下,大于1)。但是当被第二个样本减去时,它确实在这个范围内。
我将样本存储在帧缓冲纹理中,然后再组合它们。
我希望能够存储大于1的值,但是这些值被限制为1。GLSL片段着色器能输出这样的值吗?纹理能储存它们吗?如果没有,我还能怎么储存呢?
根据此页的说法,有可能:
呈现到屏幕要求输出是一种可显示的格式,在多通道管道中并不总是这样。有时,由pass生成的纹理需要有浮点格式,而不是直接转换成颜色。
但根据规范,纹理浮动夹紧范围为0,1。
发布于 2014-07-21 08:17:39
最简单的方法是使用浮点纹理。
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_buffer_float
将其呈现为浮点纹理(而且仍然需要调用gl.checkFramebufferStatus
,因为这取决于支持附件组合的驱动程序)。此外,还有EXT_float_blend
,用于在呈现为浮点纹理时是否启用混合。
发布于 2014-07-20 20:25:36
片段着色器可以在0.0、1.0范围之外输出值,但只有在将值写入缓冲区的格式以支持该范围以外的值时才能输出值。启用此功能所需的是存储浮点值的呈现目标(呈现缓冲区或附加到FBO的纹理)。
OpenGL ES 2.0及更低版本不需要对浮点格式纹理的支持。OpenGL ES 3.0及以上的do。例如,在ES3.0中,您可以使用GL_RGBA16F
作为带有16位浮点数(又称半浮点数)组件的RGBA纹理,对32位浮点数组件使用GL_RGBA32F
。但是,ES 3.0和3.1仍然不需要将这些格式用作呈现目标的支持,这正是这个用例所需要的。
ES2.0实现可以通过支持浮动提供半浮动纹理,通过支持浮动扩展提供浮动纹理。为了支持对半浮动纹理的渲染,他们还需要浮动。浮动将呈现定义为浮动纹理,但指定基于ES3.0。
总结如下:
如果您想使用这些特性,您将不得不测试这些扩展是否存在于您的设备上。
发布于 2014-07-21 03:20:50
这里的关键思想是使用0,1范围内的2或4个不动点8位通道(颜色通道)在一些不受限制的范围内对浮点数进行编码。该方法是通用的,适用于WebGL或任何其他GL系统。
让我们假设您以一个浮动值开始:
float value;
假设您的机器支持中间(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 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/
https://stackoverflow.com/questions/24855256
复制