我是靠谱客的博主 稳重短靴,最近开发中收集的这篇文章主要介绍Directx11教程四十七之Depth Of Field(视深域),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

按惯例,程序的结构如下




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(视深域)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(44)

评论列表共有 0 条评论

立即
投稿
返回
顶部