概述
按惯例,程序的结构如下
DepthOfField(视深域)的简介
视深域(DOF)是一种后处理技术,用来模拟散焦的效果。这里不讲复杂的,就讲解实时渲染中最简单的DOF实现的思路。
在DOF现象中,距离观察相机越远的物体散焦越大,这里散焦在本章节‘'简易的DOF”一定程序上等于‘"模糊’。
也就是在相机空间,计算像素与相机之间的距离,然后根据设定 的 DOFStart(DOF开始距离),DOFRange(DOF的范围)来最终计算每个像素相应的散焦效果。
好吧,不得不说,这个简易的DOF算法和Directx11教程十五之Fog(雾)的思路几乎是一样的。不过‘'DX11 雾计算’那个教程是针对单个物体的,这次的DOF是全屏的。
算法步骤:
(1)将全屏原生的ScreenRT模糊得到ScreenBlurRT
(2)利用全屏的深度缓存RT(记作DepthRT), 获取像素在屏幕空间的深度值,然后经过一定的空间变换,变为相机空间的深度值Z。
这里 “屏幕空间的深度值” - “相机空间的深度值”,参考教程软件光栅器(Directx11)四之从相机空间到视平面的坐标变换
深度缓存Z = HGSpaceZ / HGSpaceW (透视除法) , 这里假设视口最大缓存 深度为1,最小缓存深度为0
也就是 深度缓存Z = ViewSpaceZ * A + B
看上面图 A = f / (f - n) B = -(n*f) /(f-n) , f为相机的远截面距离,n为相机的近截面距离
最终逆推得到 ViewSpaceZ = ((n*f)/(n - f)) / (深度缓存Z + f / (n - f) )
如下所示:
float DepthBufferConvertToLinear(float depth)
{
float a = 1.0 /(nearPlane - farPlane);
return (nearPlane*farPlane * a) / (depth + farPlane * a);
};
(3)我们在前面两步的保证下,利用DOFStart 即DOF 开始的距离,DOFRange 即DOF影响的范围距离 来进行计算相应的像素的散焦效果,如下 所示:
Texture2D ScreenRT:register(t0);
Texture2D ScreenBlurRT:register(t1);
Texture2D DepthRT:register(t2);
SamplerState wrapLinearSample:register(s0);
SamplerState clampLinearSample:register(s1);
cbuffer CBDOF:register(b0)
{
float depthStart;
float depthRange;
float farPlane;
float nearPlane;
}
float2 texSize(Texture2D tex)
{
uint texWidth, texHeight;
tex.GetDimensions(texWidth, texHeight);
return float2(texWidth, texHeight);
}
struct VertexIn
{
float3 Pos:POSITION;
float2 Tex:TEXCOORD;
};
struct VertexOut
{
float4 Pos:SV_POSITION;
float2 Tex:TEXCOORD0;
};
float DepthBufferConvertToLinear(float depth)
{
float a = 1.0 /(nearPlane - farPlane);
return (nearPlane*farPlane * a) / (depth + farPlane * a);
};
VertexOut VS(VertexIn ina)
{
VertexOut outa;
outa.Pos = float4(ina.Pos.xy,1.0,1.0);
outa.Tex = ina.Tex;
return outa;
}
float4 PS(VertexOut outa) : SV_Target
{
float4 color = ScreenRT.Sample(clampLinearSample, outa.Tex);
float4 blurColor = ScreenBlurRT.Sample(clampLinearSample, outa.Tex);
float depth = DepthRT.Sample(clampLinearSample, outa.Tex).r;
float viewSpaceZ = DepthBufferConvertToLinear(depth);
if (depth < 1.0f)
{
float percent = saturate((viewSpaceZ - depthStart) / depthRange);
color = lerp(color, blurColor, percent);
}
color.a = 1.0;
return color;
}
未应用DOF:
应用DOF:
这里的模糊度还比较差,因为只做了乱写的简易的模糊,没有做多次的高斯模糊,模糊效果不够。当然,这是最简单的DOF算法,效果有点差,仅供学习参考。
参考资料:
【1】《HLSL Development Cook Book》 Chapater4 PostEffect
源码链接:
【1】 CSDN链接:https://download.csdn.net/download/qq_29523119/10359845
【2】github链接: https://github.com/2047241149/SDEngine
最后
以上就是稳重短靴为你收集整理的Directx11教程四十七之Depth Of Field(视深域)的全部内容,希望文章能够帮你解决Directx11教程四十七之Depth Of Field(视深域)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复