Shader 3d RayMarching3 画面(透光,锯齿,阴影波纹)优化

145 阅读3分钟

透光

2407135848

原因是因为 SURFACE_DIST 选择太小了,从 0.001->0.01 透光现象变消除了

锯齿

仔细观察图像会发现,图中边缘有锯齿

2407131140

AA 抗锯齿(Anti-Aliasing)算法用来减少和消除计算机图形学中由于像素的离散性质造成的锯齿状边缘。在渲染中,向量线条和边缘转化为像素时由于分辨率限制往往会出现这种不希望的效果。抗锯齿技术通过各种方法模糊边缘的像素,以使视觉效果更加平滑。

以下是一些常见的抗锯齿技术:

  1. SSAA(Super Sampling Anti-Aliasing,超采样抗锯齿):最直接的抗锯齿技术之一,通过以高于最终输出分辨率的分辨率渲染图像(即超采样),然后将图像缩小到目标分辨率(即降采样)来平滑边缘。这种方法会大幅度提高渲染成本。
  2. MSAA(Multi-Sampling Anti-Aliasing,多重采样抗锯齿):只对那些沿几何形状边缘的像素进行超采样,对于纯颜色区域内部的像素不做处理。这样节省了资源并减少了性能开销。
  3. FXAA(Fast Approximate Anti-Aliasing,快速近似抗锯齿):通过在图像后处理阶段应用像素着色器,检测像素的邻域并平滑那些可能产生锯齿的边缘。FXAA相较于SSAA和MSAA更快,但可能会导致图像略微模糊。
  4. TXAA(Temporal Anti-Aliasing,时间抗锯齿):利用相邻帧之间的信息来产生更平滑的边缘。这种方法也常与其他抗锯齿技术结合使用,可减少运动时产生的锯齿和闪烁。
  5. SMAA(Subpixel Morphological Anti-Aliasing,次像素形态抗锯齿):结合了MSAA的优势和后处理抗锯齿技术,侦测次像素级的纹理模式,并进行形态学操作来平滑锯齿。
  6. CSAA(Coverage Sampling Anti-Aliasing,覆盖率采样抗锯齿)和EQAA(Enhanced Quality Anti-Aliasing,增强质量抗锯齿):这些是特定于平台(如NVIDIA和AMD)的抗锯齿技术,它们结合了多重采样和超采样的原理,并尝试在不牺牲太多性能的情况下提高图像质量。
  7. DLAA(Deep Learning Anti-Aliasing,深度学习抗锯齿):是较新的一种方法,使用机器学习算法,尤其是深度学习来训练网络识别和平滑锯齿边缘。

这里实现最简单的超采样抗锯齿,最开始定义一个宏

#define AA 2

如果AA > 1, 则进行超采样,AA=2表示采样4次

    vec3 tot = vec3(0.0);

#if AA>1
    for( int m=0; m<AA; m++ )
    for( int n=0; n<AA; n++ )
    {
    // pixel coordinates
    vec2 o = vec2(float(m),float(n)) / float(AA) - 0.5;
    vec2 uv = (-iResolution.xy + 2.0*(fragCoord+o))/iResolution.y;
#else    
    vec2 uv = (-iResolution.xy + 2.0*fragCoord)/iResolution.y;
#endif

上面将坐标左右上下移动0.5个像素点。进行计算,当绘图计算完成之后

    tot += col;
#if AA>1
    }
    tot /= float(AA*AA);
#endif
    fragColor = vec4( tot, 1.0 ); 

如果采用了超采样,将4个值累加并 除4。 最后我们得到更加柔和无锯齿的球啦~

2407125416

阴影波纹

在光不停在上空盘旋,阴影有时候会出现波纹,如下图所示 2407131231

原因是我们的marching长度选的太大了,只需要优化一下march算法,为每次march不小于0.01, 修改一行代码就可

float GetShadow(vec3 ro, vec3 rd, float mint, float maxt, float k) {
	float res = 1.0;
    float t = mint;
    for( int i=0; i<MAX_STEPS && t<maxt; i++ )
    {
        float h = GetDist(ro + rd*t);
        if( h<SURFACE_DIST )
            return 0.0;
		res = min( res, k*h/t );
        //t += h;
        t += max(0.01, .5 *h);
    }
    return res;
}