[OpenGL]利用帧缓冲和深度测试制造雾霾和景深效果

这两天又开始捣鼓图形这块的,终究游戏引擎之心未死(但是直到目前都还是很基础的状态)。

之前看到有些游戏里景深的效果非常的棒,可以营造一些效果吸引玩家的注意力。刚好这两天看的深度测试和帧缓冲,感觉两者合并一下可以做出这个效果于是试了一下。

先看效果:

sample

可以看到,离得近的物体边缘是比较清楚的,而离得远的地方就很模糊了。而且离得远的地方渐渐有雾霾一样的东西。

雾霾效果

道理其实非常简单,我们把背景色设置成雾的颜色,然后在渲染每个点的时候,把离我们远的点的颜色调得接近背景色,越远越浓就行。

在GLSL中,我们先在顶点着色器中完成了坐标变换,在片段着色器中可以获取到当前片段的坐标值,这个坐标的z值就反映了这块片段离我们摄像机的距离:

gl_FragCoord.z

但是这个z和实际的距离相比不是线性的,在离我们近的地方精度高,离我们远的地方则精度低(是openGL为了提高深度测试的精度,因为要渲染的物体细节在离我们比较近的地方,我感觉类似于通信中的A率压缩之类的)

那么我们需要做一个转换让它变得线性,更能体现实际的距离:

float LinearizeDepth(float depth) 
{
    float z = depth * 2.0 - 1.0; // back to NDC 
    return (2.0 * near * far) / (far + near - z * (far - near));    
}

于是我们就有了片段的深度值,在输出颜色的时候做以下的操作,便可以得到类似于雾霾的效果:

FragColor = texture(texture_diffuse1, TexCoords) * (1.0 - depth) + clearColor*(depth);

离我们越近时输出原色越接近于纹理颜色,离我们越远时月接近背景色。

景深效果

我这个景深效果有点问题,就是正常的景深应该是在焦点处清晰,而距离大于或者小于焦距时都会模糊。但是这里是越近越清晰越远越模糊。。。

那么想做这个效果,我们就有两个问题:

  1. 距离

  2. 模糊

幸好根据上面的雾霾我们已经可以得到片段离我们的距离,那我们来制造模糊的效果:

在数字图像处理中我们知道想要模糊一张图片,有一个很快速很简单(虽然效果比较差)的方法:用核操作实现一个低通滤波器

这个能实现低通滤效果的核可以有很多种了,我们选一个比较简单的:

    float kernel[9] = float[](
        1.0/9.0, 1.0/9.0, 1.0/9.0, 
        1.0/9.0, 1.0/9.0, 1.0/9.0, 
        1.0/9.0, 1.0/9.0, 1.0/9.0
    );

然后我们根据每个片段离我们不同的距离来决定模糊的强度。但是在实现景深之前,我们得先拿到不模糊的图啊。所以我们需要先把没有景深效果的图给渲染到一张纹理里面,然后再次把这张纹理渲染到屏幕上。这里就要用到帧缓冲。

额帧缓冲的介绍请参考下面的参考链接。

大概就是这样个流程:

  1. 正常渲染场景物体,结果存到一张纹理中;

  2. 再次渲染场景物体,但是只输出它的深度值,结果存到另一张纹理中;

  3. 渲染一个矩形(铺满屏幕),使用上面渲染好的纹理作为现在这个矩形的纹理(上面有俩)并且进行模糊操作。

模糊的时候,我们根据物体的深度给核操作一个不同的采样距离,也就能得到不同的模糊效果。

以下是一个动图:

当然也可以反过来搞那就是近的模糊远的清楚的效果:

sample

额我知道说是肯定说不清楚的,源码放在了这里

以及编译好的例子

参考链接:

我是看这个教程写的 LearnOpenGL CN

发表评论

电子邮件地址不会被公开。