opengl-es - SSAO 深度后处理期间的抗锯齿

标签 opengl-es html5-canvas webgl antialiasing ssao

我需要增强一些具有非常精细细节的机械部件的视觉感知,因此我现在正在尝试 screen.space 环境光遮挡的不同实现。

到目前为止,我通过使用 gl.TRIANGLES 在前向渲染中将几何图形直接绘制到屏幕上,将 Canvas 分辨率加倍,并启用抗锯齿on,例如,假设我的 Canvas 样式是 800x600 px,那么我的 Canvas 宽度/高度设置为 1600x1200。只有将屏幕抗锯齿与如此高分辨率结合使用,我才能获得所需的视觉质量。

通过使用渲染缓冲区,即使以双倍分辨率渲染,由于缺乏抗锯齿功能,我也无法接近所需的质量。我尝试在额外的后处理步骤中实现许多不同的抗锯齿技术,但无论如何我无法获得干净、平滑的线条。这是我的意思的一个例子:看看图像底部的长的、稍微旋转的部分。

antialiasing missed in renderbuffer

是否有任何方法可以通过在屏幕空间后处理过程中在后台缓冲区中绘制来获得干净、抗锯齿的线条?任何有关其他策略/技术的额外提示将不胜感激。

是否有人在 SSAO 过程中成功实现了 - 仅举一个例子 - FXAA 或类似的东西,以获得平滑的抗锯齿长对角线,而不会出现锯齿?

<小时/>

这是与上图相关的片段着色器:

float compareDepths(in float depth1,in float depth2, in float aoMultiplier) {
    float aoCap = 1.0;
    float diff = sqrt( clamp(1.0-(depth1-depth2) / (u_aoRange/(u_zFar-u_zNear)),0.0,1.0) );
    float ao = min(aoCap,max(0.0, depth1 - depth2 - u_depthTolerance) * aoMultiplier) * diff;
    return ao;
}
void main(void) {
    vec2 UV = v_texCoord.st;
    float depth = readDepth(UV);
    float d;
    float pw = 1.0 / u_resolution.x;
    float ph = 1.0 / u_resolution.y;
    float aoCap = 1.0;
    float ao = 0.0;
    float aoMultiplier = u_aoMultiplier;

    // 4 samples w/out loop
    float aoscale=1.0;
    d=readDepth( vec2(UV.x+pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x+pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;

    pw*=2.0;
    ph*=2.0;
    aoMultiplier/=2.0;
    aoscale*=1.2;
    d=readDepth( vec2(UV.x+pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x+pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;

    pw*=2.0;
    ph*=2.0;
    aoMultiplier/=2.0;
    aoscale*=1.2;
    d=readDepth( vec2(UV.x+pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x+pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;

    pw*=2.0;
    ph*=2.0;
    aoMultiplier/=2.0;
    aoscale*=1.2;
    d=readDepth( vec2(UV.x+pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y+ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x+pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;
    d=readDepth( vec2(UV.x-pw,UV.y-ph));
    ao+=compareDepths(depth, d, aoMultiplier)/aoscale;

    ao/=16.0;',
    gl_FragColor = vec4( vec3(1.0-ao), 1.0 );
}

编辑:

下面我使用了 John Chapman 在这篇伟大的 SSAO Tutorial 中描述的 SSAO 技术。 .

左为四倍分辨率,右为全分辨率,带有分离的高斯模糊。

comparison

请注意,使用一些经典的更“有机”或“弯曲”模型(例如茶壶斯坦福龙)不会干扰这些文物或快乐佛。这些文物在规则的几何长物体、典型的机械或建筑形状中很明显。

是否有任何方法可以通过保持质量并保留高频细节来增强深度感知,而不使用四倍的 Canvas 分辨率?

编辑2:

最终结果在视网膜显示屏上的全 Canvas 尺寸下看起来非常好,例如在 iPad 上,其分辨率为每英寸 264 像素。然而,锯齿状线条在通常为 70 或 92 DPI 的桌面显示器上清晰可见且令人不安。

我发现了这篇文章:multiresolution ambient occlusion来自 Íñigo Quílez,其中还包含一些关于高频遮挡 - 程序遮挡的提示,以增强微小的细节,但我无法理解这是否也适用于直线几何形状。有人已经做过这个实验了吗?

编辑3:

这是我迄今为止找到的关于此主题的最有用的引用:Fast Prefiltered Lines来自GPU Gems 2。 有人已经与 SSAO 一起实现了此处描述的技术?

最佳答案

屏幕空间环境光遮挡捕获低频照明。它不会捕捉锐利的阴影或漫反射或镜面照明。因此,SSAO 通常与漫反射和镜面照明相结合来创建完整的照明解决方案。

SSAO 在 3D 渲染场景中展示全局光照效果作为后期效果。它可以快速逼近昂贵的光线追踪全局照明。因此,在某些情况下(例如您的情况)可能会出现伪影。

SSAO 很少可以开箱即用,但需要一些调整。设置过程包括调整内核半径样本数以获得所需的效果。 内核半径取决于场景的自然比例。最初可能看起来根本没有 SSAO。此时,Kernel Radius 要么太小,要么太大,必须找到工作值。请记住:SSAO 在 CPU 上的速度非常慢,但在 GPU 上的性能要好得多。

解决方案: 将多个 SSAO 渲染 channel 与不同的Kernel Radii相结合可以产生更好的效果。

看图片的右下角:

(三个相乘图像产生具有某些细节的最终图像)

enter image description here

关于opengl-es - SSAO 深度后处理期间的抗锯齿,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48523905/

相关文章:

ios - 如何在 iOS(增强现实应用程序)中的实时预览相机上制作 OpenGL ES 的屏幕截图?

javascript - 按键干扰 canv.onmousedown();

javascript - fillStyle 不是函数

javascript - ThreeJS 创造一个太阳

webgl - 如何从 geoserver 获取 3dmodesl(dae,obj,etc) 作为图层

安卓游戏开发。

ios - OpenCV + OpenGL : proper camera pose using solvePnP

android - QVideoFrame::map() 崩溃

javascript - 如何使用 html5-canvas 拖动连接线

javascript - 将位图字符转换为三 Angular 形