Opengl es 如何在webgl中的渲染过程之间传递高精度uv坐标?
假设我正在处理WebGL中的一个问题,该问题要求从大纹理中检索值,例如,2048x2048,精度达到像素级 到目前为止,一切都很顺利。我可以将大纹理传递给片段着色器,片段着色器将其转换为渲染目标,我甚至可以将该渲染目标作为另一个渲染过程的输入,始终检索我需要的确切像素 但现在我想把事情搞混。我想创建一个渲染过程,该过程返回一个纹理,该纹理为我开始使用的大纹理中的每个像素存储一对uv坐标。作为最简单的用例,我们假设:Opengl es 如何在webgl中的渲染过程之间传递高精度uv坐标?,opengl-es,three.js,glsl,webgl,shader,Opengl Es,Three.js,Glsl,Webgl,Shader,假设我正在处理WebGL中的一个问题,该问题要求从大纹理中检索值,例如,2048x2048,精度达到像素级 到目前为止,一切都很顺利。我可以将大纹理传递给片段着色器,片段着色器将其转换为渲染目标,我甚至可以将该渲染目标作为另一个渲染过程的输入,始终检索我需要的确切像素 但现在我想把事情搞混。我想创建一个渲染过程,该过程返回一个纹理,该纹理为我开始使用的大纹理中的每个像素存储一对uv坐标。作为最简单的用例,我们假设: precision highp float; precision highp s
precision highp float;
precision highp sampler2D;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(vUv, 0, 1);
}
使用此第一次渲染过程返回的uv坐标,我希望从我开始使用的大纹理中访问一个像素:
precision highp float;
precision highp sampler2D;
uniform sampler2D firstPass;
uniform sampler2D largeTexture;
varying vec2 vUv;
void main() {
vec2 uv = texture2D(firstPass, vUv);
gl_FragColor = texture2D(largeTexture, uv);
}
然而,这并不具有足够的精度。我通常会从相邻的像素中得到一种颜色,而不是我想要处理的像素。通过一些修补,我发现这只适用于大小高达~512x512的纹理
您会注意到,我在这些示例中指定了高精度浮点和取样器2D的使用。这是我脑海中浮现的唯一解决方案,但这仍然不能解决我的问题。我知道我总是可以使用相对坐标系来寻址需要较低精度的像素,但为了简单起见,我希望我仍然能够使用uv来寻址。
将UV纹理设置为浮点纹理?当前,每个通道的纹理可能只有8位,这意味着它只能处理256个唯一位置。浮点纹理不会有这个问题
不幸的是,并非所有地方都支持对浮点纹理进行渲染,浏览器也没有统一实现所需的扩展来检查它是否有效。如果你在一个现代的桌面上,它很可能会工作
要确定它是否有效,请尝试获取浮点纹理扩展,如果它存在,请创建浮点纹理并将其附加到帧缓冲区,然后检查帧缓冲区是否完整。如果是,您可以渲染到它
var floatTextures = gl.getExtension("OES_texture_float");
if (!floatTextures) {
alert("floating point textures are not supported on your system");
return;
}
// If you need linear filtering then...
var floatLinearTextures = gl.getExtension("OES_texture_float_linear");
if (!floatLinearTextures) {
alert("linear filtering of floating point textures is not supported on your system");
}
// check if we can render to floating point textures.
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);
// some drivers have a bug that requires you turn off filtering before
// rendering to a texture.
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
// make a framebuffer
var fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
// attach the texture
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D, tex, 0);
// check if we can render
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (status != gl.FRAMEBUFFER_COMPLETE) {
alert("can't render to floating point textures");
return;
}
// You should be good to go.
通过将数据组合到多个通道中来提高分辨率
写入UV纹理时,将UV从0-1范围转换为0到65535范围,然后将modfuv、256/255写入一个通道,将flooruv/256/256写入另一个通道。读取时,使用uv=低通道*256.0+高通道*65535.0/65535.0等方式重新组合通道
这应该适用于任何地方,并为您提供足够的分辨率来处理65536x65536纹理
想法
将UV纹理设置为浮点纹理?当前,每个通道的纹理可能只有8位,这意味着它只能处理256个唯一位置。浮点纹理不会有这个问题
不幸的是,并非所有地方都支持对浮点纹理进行渲染,浏览器也没有统一实现所需的扩展来检查它是否有效。如果你在一个现代的桌面上,它很可能会工作
要确定它是否有效,请尝试获取浮点纹理扩展,如果它存在,请创建浮点纹理并将其附加到帧缓冲区,然后检查帧缓冲区是否完整。如果是,您可以渲染到它
var floatTextures = gl.getExtension("OES_texture_float");
if (!floatTextures) {
alert("floating point textures are not supported on your system");
return;
}
// If you need linear filtering then...
var floatLinearTextures = gl.getExtension("OES_texture_float_linear");
if (!floatLinearTextures) {
alert("linear filtering of floating point textures is not supported on your system");
}
// check if we can render to floating point textures.
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);
// some drivers have a bug that requires you turn off filtering before
// rendering to a texture.
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
// make a framebuffer
var fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
// attach the texture
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D, tex, 0);
// check if we can render
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (status != gl.FRAMEBUFFER_COMPLETE) {
alert("can't render to floating point textures");
return;
}
// You should be good to go.
通过将数据组合到多个通道中来提高分辨率
写入UV纹理时,将UV从0-1范围转换为0到65535范围,然后将modfuv、256/255写入一个通道,将flooruv/256/256写入另一个通道。读取时,使用uv=低通道*256.0+高通道*65535.0/65535.0等方式重新组合通道
这应该适用于任何地方,并为您提供足够的分辨率来处理65536x65536纹理
到目前为止,我已经使用了浮点纹理,效果非常好。该项目是一个内部应用程序,考虑到支持浮点纹理的浏览器的数量,我认为这不会是一个问题。具有讽刺意味的是,Three.js的使用使采用浮点纹理变得复杂,但幸运的是,在Three.Texture和Three.WebGLRenderTarget的构造函数中已经有了一个指定浮点的选项。谢谢到目前为止,我已经使用了浮点纹理,效果非常好。该项目是一个内部应用程序,考虑到支持浮点纹理的浏览器的数量,我认为这不会是一个问题。具有讽刺意味的是,Three.js的使用使采用浮点纹理变得复杂,但幸运的是,在Three.Texture和Three.WebGLRenderTarget的构造函数中已经有了一个指定浮点的选项。谢谢