Unity Shader 屏幕后效果——景深
景深效果的原理是,在摄像机的近裁剪平面和远裁剪平面之间可以设置一个焦距,在这个距离所在的平面上的物体最为清晰,而这个距离之前或之后的物体成像是一种模糊状态(根据距离逐渐模糊,最终达到最为模糊的状态)。
在shader中,需要一张清晰的场景图和一张模糊的场景图,可以通过每个像素相对焦距的距离来判定这个像素最终的清晰程度。在清晰图和模糊图之间做关于深度变化的插值运算。
关于摄像机的近裁剪平面和远裁剪平面,可以直接在Camera组件的属性面板中调节(默认的远裁剪平面距离是1000):

模糊图可以直接采用高斯模糊实现,具体参考:
https://www.cnblogs.com/koshio0219/p/11152534.html
清晰图也就是未经过任何处理的渲染图,直接就可以得到;
关键问题在于如何得到每个像素在摄像机近裁剪平面和远裁剪平面之间的位置,而这个位置信息就是渲染纹理的深度值。
在Unity中,可以不用自己计算深度值,Unity提供了直接提取摄像机深度值的宏:
float depth=SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv_depth);
depth=Linear01Depth(depth);
并可以直接利用内置函数将其转化为线性深度值(对于透视摄像机来说,原本的深度值是非线性的),以方便后续的插值计算。
在提取摄像机深度值之前,需要将摄像机的深度纹理模式设置为Depth,同时在Shader中提前声明_CameraDepthTexture变量:
MyCamera.depthTextureMode |= DepthTextureMode.Depth;
sampler2D _CameraDepthTexture;
C#控制脚本如下:
using UnityEngine; public class DepthOfFieldCrtl : ScreenEffectBase
{
private const string _BlurSize = "_BlurSize";
private const string _FocusDistance = "_FocusDistance";
private const string _BlurTex = "_BlurTex"; //用于控制高斯模糊的参数
[Range(.2f,)]
public float blurSize = .6f;
[Range(, )]
public int iterations = ;
[Range(, )]
public int downSample = ; //归一化后的焦距,0表示焦距处于摄像机近裁剪平面,1表示处于远裁剪平面;为了更好的调整效果,可以将[0,1]范围适当扩大
[Range(-.02f, 1.02f)]
public float focusDistance = .5f; private Camera myCamera=null;
public Camera MyCamera
{
get
{
if (myCamera == null)
{
myCamera = GetComponent<Camera>();
}
return myCamera;
}
} //开启摄像机深度模式
private void OnEnable()
{
MyCamera.depthTextureMode |= DepthTextureMode.Depth;
} //不用时还原
private void OnDisable()
{
MyCamera.depthTextureMode &= ~DepthTextureMode.Depth;
} private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (Material)
{
//传递焦距
Material.SetFloat(_FocusDistance, focusDistance); var w = source.width / downSample;
var h = source.height / downSample; var buffer0 = RenderTexture.GetTemporary(w, h, );
buffer0.filterMode = FilterMode.Bilinear; Graphics.Blit(source, buffer0); //前两个Pass做高斯模糊处理,结果保存在buffer0中
for(int i = ; i < iterations; i++)
{
Material.SetFloat(_BlurSize, blurSize*i+1.0f); var buffer1 = RenderTexture.GetTemporary(w, h, );
buffer1.filterMode = FilterMode.Bilinear;
Graphics.Blit(buffer0, buffer1, Material, );
RenderTexture.ReleaseTemporary(buffer0); buffer0 = RenderTexture.GetTemporary(w, h, );
Graphics.Blit(buffer1, buffer0, Material, );
RenderTexture.ReleaseTemporary(buffer1);
} //最后一个Pass用原图像和模糊图(buffer0)进行关于深度的插值计算,具体见Shader脚本
Material.SetTexture(_BlurTex, buffer0);
Graphics.Blit(source, destination,Material,);
RenderTexture.ReleaseTemporary(buffer0);
}
else
Graphics.Blit(source, destination); }
}
基类脚本见:
https://www.cnblogs.com/koshio0219/p/11131619.html
Shader脚本:
Shader "MyUnlit/DepthOfFiled"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
CGINCLUDE #include "UnityCG.cginc" sampler2D _MainTex;
sampler2D _BlurTex;
//声明摄像机深度
sampler2D _CameraDepthTexture;
half4 _MainTex_TexelSize;
fixed _FocusDistance; struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
}; struct v2f
{
half4 uv:TEXCOORD0;
half2 uv_depth:TEXCOORD1;
float4 vertex:SV_POSITION;
}; v2f vert(appdata v)
{
v2f o;
o.vertex=UnityObjectToClipPos(v.vertex); //xy存储清晰纹理,zw存储模糊纹理
o.uv.xy=v.uv;
o.uv.zw=v.uv;
o.uv_depth=v.uv; //需要对模糊纹理和深度纹理进行平台差异化处理
#if UNITY_UV_STARTS_AT_TOP
if(_MainTex_TexelSize.y<){
o.uv.w=1.0-o.uv.w;
o.uv_depth.y=1.0-o.uv_depth.y;
}
#endif return o;
} fixed4 frag(v2f i):SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv.xy);
fixed4 bcol=tex2D(_BlurTex,i.uv.zw); //得到深度值并线性归一化
float depth=SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv_depth);
depth=Linear01Depth(depth); //因为焦距也是设置的归一化的值,直接相减取绝对值即得到模糊系数,返回插值结果
fixed bVa=abs(depth-_FocusDistance);
return lerp(col,bcol,bVa);
} ENDCG ZTest Always
Cull Off
ZWrite Off //前两个Pass高斯模糊
UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_V" UsePass "MyUnlit/GaussianBlur/GAUSSIANBLUR_H" Pass
{
CGPROGRAM #pragma vertex vert
#pragma fragment frag ENDCG
}
}
FallBack Off
}
效果如下:
(注意调整摄像机近裁剪平面和远裁剪平面的值处于合适的区间)


Unity Shader 屏幕后效果——景深的更多相关文章
- Unity Shader 屏幕后效果——颜色校正
屏幕后效果指的是,当前整个场景图已经渲染完成输出到屏幕后,再对输出的屏幕图像进行的操作. 在Unity中,一般过程通常是: 1.建立用于处理效果的shader和临时材质,给shader脚本传递需要控制 ...
- Unity Shader 屏幕后效果——边缘检测
关于屏幕后效果的控制类详细见之前写的另一篇博客: https://www.cnblogs.com/koshio0219/p/11131619.html 这篇主要是基于之前的控制类,实现另一种常见的屏幕 ...
- Unity Shader 屏幕后效果——全局雾
Unity内置的雾效需要在每个shader中分别编写,造成了极大的不便.这里利用屏幕后处理产生可单独控制且自由度更高的雾效. 屏幕后雾效的本质在于,通过深度纹理重构出每个像素在世界空间中的位置,根据得 ...
- Unity Shader 屏幕后效果——高斯模糊
高斯模糊是图像模糊处理中非常经典和常见的一种算法,也是Bloom屏幕效果的基础. 实现高斯模糊同样用到了卷积的概念,关于卷积的概念和原理详见我的另一篇博客: https://www.cnblogs.c ...
- Unity Shader 屏幕后效果——Bloom外发光
Bloom的原理很简单,主要是提取渲染图像中的亮部区域,并对亮部区域进行模糊处理,再与原始图像混合而成. 一般对亮部进行模糊处理的部分采用高斯模糊,关于高斯模糊,详见之前的另一篇博客: https:/ ...
- Unity Shader 屏幕后效果——摄像机运动模糊(速度映射图实现)
速度映射图主要是为了得到每个像素相对于前一帧的运动矢量,其中一种方法是使用摄像机的深度纹理来推导. 推导过程如下: 先由深度纹理逆推出NDC(归一化的设备坐标)下的顶点坐标,利用VP矩阵(视角*投影矩 ...
- Unity Shader实现描边效果
http://gad.qq.com/article/detail/28346 描边效果是游戏里面非常常用的一种效果,一般是为了凸显游戏中的某个对象,会给对象增加一个描边效果.本篇文章和大家介绍下利用S ...
- Unity Shader 之 透明效果
透明效果 透明效果一般有两种实现方法: 第一种,使用透明度测试(Alpha Test) 第二种,使用透明度混合(Alpha Blending) 透明度测试和透明度混合机制: 透明度测试(Alpha T ...
- Unity实现屏幕抖动效果(通过Camera Viewpoint实现)
由于游戏死亡时一般都需要屏幕抖一下下. 所以百度了下相关写法,发现方法很多~~~ 找来找去,找到个简单粗暴地,啥都不需要,一个脚本拖动到Camera上就可以了 略微修改了一点点,share一下 usi ...
随机推荐
- c# Equal函数 and 运算符'==' (原发布 csdn 2017年10月15日 20:39:26)
1.==.!=.<.>.<= 和>= 运算符为比较运算符(comparison operator).C#语言规范5.0中文版中比较运算符的描述如下: 2.通用类型系统 3.值类 ...
- Gitlab的CI/CD初尝试
初衷:今天公司的前端和测试人员吵起来了.原因是测试埋怨前端人员把Bug的状态更改为已解决,结果代码根本没提交,而前端人员埋怨测试测的太频繁了,需要打几个环境的包不方便.又要改东西又要频繁打包费时间.凡 ...
- Java基础—内部类
在Java语言中,可以把一个类定义到另一个类的内部,在类里面的这个类就叫作内部类,外面的类叫作外部类.在这种情况下,这个内部类可以被看成外部类的是一个成员(与类的属性和方法类似).还有一种类被称为顶层 ...
- linux桌面系统的约定
linux系统的桌面系统基本遵循同样的约定. mime类型 在linux下,关于文件类型的信息通常放在/usr/share/mime./usr/local/share/mime和用户目录下,所有应用程 ...
- LR实现处理PUT方法的案例
- css中的baseline
这是css中的一个容易被人忽略的概念,今天在知乎上看到一个问题,这个问题应该是关于baseline,才去补习了一下关于baseline的知识,首先我来还原一下问题: <div style=&qu ...
- vue cli 3.0快速创建项目
本地安装vue-cli 前置条件 更新npm到最新版本 命令行运行: npm install -g npmnpm就自动为我们更新到最新版本 淘宝npm镜像使用方法 npm config set reg ...
- 【IPHONE开发-OBJECTC入门学习】文件的操作,读写复制文件
转自:http://blog.csdn.net/java886o/article/details/9041547 FileTools.h FileTools.m #import "FileT ...
- Vue实战狗尾草博客管理系统第一章
Vue实战狗尾草博客后台管理系统第一章 这里准备采用的技术栈为:vue全家桶+element-ui 这里因为是后台管理系统,没有做SSR的必要.所以这里就采用前后端分离来昨晚这个项目~ 项目搭建 vu ...
- 关于oracle PL/SQL存储过程 PLS-00905 object is invalid,statement ignored问题的解决
昨天在学习oracle存储过程的时候,写了一个存储过程的demo,语句是这样的: )) AS psssal TESTDELETE.TESTID%TYPE; BEGIN SELECT TESTID IN ...