运动模糊之深度纹理:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MotinBlurWithDepthTexture : PostEffectBase
{
[Range(0, 1f)]
public float blurSize = 0.5f;
public Camera currentCamera;
private Matrix4x4 previousViewProjectionMatrix;
private void OnEnable()
{
currentCamera.depthTextureMode |= DepthTextureMode.Depth;
previousViewProjectionMatrix = currentCamera.projectionMatrix * currentCamera.worldToCameraMatrix;
}
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (material != null)
{
material.SetFloat("_BlurSize", blurSize);
material.SetMatrix("_PreviousViewProjectionMatrix",previousViewProjectionMatrix);
Matrix4x4 currentViewProjectionMatrix = currentCamera.projectionMatrix * currentCamera.worldToCameraMatrix;
Matrix4x4 currentViewProjectionInverseMatrix = currentViewProjectionMatrix.inverse;
material.SetMatrix("_CurrentViewProjectionInverseMatrix",currentViewProjectionInverseMatrix);
previousViewProjectionMatrix = currentViewProjectionMatrix;
Graphics.Blit(source,destination,material);
}
else
{
Graphics.Blit(source, destination);
}
}
}
Shader "Unlit/311" {
Properties{
_MainTex("Base (RGB)", 2D) = "white" {}
_BlurSize("Blur Size", Float) = 1.0
}
SubShader{
//CGINCLUDE可以避免两个完全一样的frag函数
//Unity会把 CGINCLUDE 和 ENDCG 之间的代码插入到每一个pass中,已达到声明一遍,多次使用的目的。
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
half4 _MainTex_TexelSize;
//Unity传进来的深度纹理
sampler2D _CameraDepthTexture;
//矩阵在这里写了,CS脚本可以直接赋值
float4x4 _CurrentViewProjectionInverseMatrix;
float4x4 _PreviousViewProjectionMatrix;
half _BlurSize;
struct v2f {
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
half2 uv_depth : TEXCOORD1;
};
v2f vert(appdata_img v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
o.uv_depth = v.texcoord;
//当为DirectX平台时,需要做翻转
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
o.uv_depth.y = 1 - o.uv_depth.y;
#endif
return o;
}
fixed4 frag(v2f i) : SV_Target {
//使用UV坐标对深度纹理采样得到深度值
float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth);
//取NDC坐标 d*2-1即可
float4 H = float4(i.uv.x * 2 - 1, i.uv.y * 2 - 1, d * 2 - 1, 1);
//逆矩阵变换
float4 D = mul(_CurrentViewProjectionInverseMatrix, H);
//世界坐标下下的位置
float4 worldPos = D / D.w;
//当前位置
float4 currentPos = H;
//上一帧位置
float4 previousPos = mul(_PreviousViewProjectionMatrix, worldPos);
// Convert to nonhomogeneous points [-1,1] by dividing by w.
previousPos /= previousPos.w;
//计算与上一帧的位置差,得到速度
float2 velocity = (currentPos.xy - previousPos.xy) / 2.0f;
//得到速度后,利用速度对附近像素进行采样现到新的色值
float2 uv = i.uv;
float4 c = tex2D(_MainTex, uv);
uv += velocity * _BlurSize;
for (int it = 1; it < 3; it++, uv += velocity * _BlurSize) {
float4 currentColor = tex2D(_MainTex, uv);
c += currentColor;
}
c /= 3;
return fixed4(c.rgb, 1.0);
}
ENDCG
//下面是动态模糊所需要的Pass
Pass {
ZTest Always Cull Off ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
FallBack Off
}
全局雾效:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FogWithDepthTexture : PostEffectBase
{
private Camera myCamera;
public Camera MyCamera
{
get
{
if (myCamera == null)
{
myCamera = GetComponent<Camera>();
}
return myCamera;
}
}
private Transform cameraTransform;
public Transform CameraTransform
{
get
{
if (cameraTransform == null)
{
cameraTransform = MyCamera.transform;
}
return cameraTransform;
}
}
[Range(0, 3f)]
public float fogDensity = 0.5f;
public Color fogColor = Color.white;
public float fogStart = 0;
public float fogEnd = 2;
private void OnEnable()
{
MyCamera.depthTextureMode |= DepthTextureMode.Depth;
}
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (material != null)
{
Matrix4x4 frustumCorners = Matrix4x4.identity;
float fov = MyCamera.fieldOfView;
float near = MyCamera.nearClipPlane;
float far = MyCamera.farClipPlane;
float aspect = MyCamera.aspect;
float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
Vector3 toRight = CameraTransform.right * halfHeight * aspect;
Vector3 toTop = CameraTransform.up * halfHeight;
Vector3 topLeft = CameraTransform.forward * near + toTop - toRight;
float scale = topLeft.magnitude / near;
topLeft.Normalize();
topLeft *= scale;
Vector3 topRight = CameraTransform.forward * near + toTop + toRight;
topRight.Normalize();
toRight *= scale;
Vector3 bottomLeft = CameraTransform.forward * near - toTop - toRight;
bottomLeft.Normalize();
bottomLeft *= scale;
Vector3 bottomRight = CameraTransform.forward * near - toTop + toRight;
bottomRight.Normalize();
bottomRight *= scale;
frustumCorners.SetRow(0, bottomLeft);
frustumCorners.SetRow(1, bottomRight);
frustumCorners.SetRow(2, topRight);
frustumCorners.SetRow(3, topLeft);
material.SetMatrix("_FrustumCornersRay", frustumCorners);
material.SetMatrix("_ViewProjectionInverseMatrix", (MyCamera.projectionMatrix * MyCamera.worldToCameraMatrix).inverse);
material.SetFloat("_FogDensity", fogDensity);
material.SetColor("_FogColor", fogColor);
material.SetFloat("_FogStart", fogStart);
material.SetFloat("_FogEnd", fogEnd);
Graphics.Blit(source, destination, material);
}
else
{
Graphics.Blit(source, destination);
}
}
}
Shader "Unlit/32"
{
Properties
{
_MainTex("Base (RGB)", 2D) = "white" {}
_FogDensity("FogDensity",Float) = 1.0
_FogColor("FogColor",Color) = (1,1,1,1)
_FogStart("FogStart",Float) = 0.0
_FogEnd("FogEnd",Float) = 2.0
}
SubShader
{
CGINCLUDE
#include "UnityCG.cginc"
float4x4 _FrustumCornersRay;
sampler2D _MainTex;
half4 _MainTex_TexelSize;
sampler2D _CameraDepthTexture;
half _FogDensity;
fixed4 _FogColor;
float _FogStart;
float _FogEnd;
struct v2f {
float4 pos : SV_POSITION;
half2 uv : TEXCOORD0;
half2 uv_depth : TEXCOORD1;
float4 interpolatedRay : TEXCOORD2;
};
v2f vert(appdata_img v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord;
o.uv_depth = v.texcoord;
#if UNITY_UV_STATS_AT_TOP
if (_MainTex_TexelSize.y < 0)
o.uv_depth.y = 1 - o.uv_depth.y;
#endif
int index = 0;
if (v.texcoord.x < 0.5 && v.texcoord.y < 0.5)
{
index = 0;
}
else if (v.texcoord.x > 0.5 && v.texcoord.y < 0.5)
{
index = 1;
}
else if (v.texcoord.x > 0.5 && v.texcoord.y > 0.5)
{
index = 2;
}
else
{
index = 3;
}
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
index = 3 - index;
#endif
o.interpolatedRay = _FrustumCornersRay[index];
return o;
}
fixed4 frag(v2f i) :SV_Target
{
float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv_depth));
float3 worldPos = _WorldSpaceCameraPos + linearDepth * i.interpolatedRay.xyz;
float fogDensity = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart);
fogDensity = saturate(fogDensity * _FogDensity);
fixed4 finalColor = tex2D(_MainTex,i.uv);
finalColor.rgb = lerp(finalColor.rgb, _FogColor.rgb, fogDensity);
return finalColor;
}
ENDCG
Pass
{
ZTest Always Cull Off ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
Fallback Off
}
边缘检测:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EdgeDetectNormalAndDepth : PostEffectBase
{
public float edgesOnly = 0;
public Color edgeColor = Color.black;
public Color backgroundColor = Color.white;
public float sampleDistance = 1f;
public float sensitivityDepth = 1f;
public float sensitivityNormals = 1f;
public Vector2 v1;
private void OnEnable()
{
GetComponent<Camera>().depthTextureMode |= DepthTextureMode.DepthNormals;
}
[ImageEffectOpaque]
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (material != null)
{
material.SetFloat("_EdgeOnly", edgesOnly);
material.SetColor("_EdgeColor", edgeColor);
material.SetColor("_BackgroundColor", backgroundColor);
material.SetFloat("_SampleDistance", sampleDistance);
material.SetVector("_Sensitivity", new Vector4(sensitivityNormals, sensitivityDepth, 0, 0));
Graphics.Blit(source, destination, material);
}
else
{
Graphics.Blit(source, destination);
}
}
}
Shader "Unlit/33"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_EdgeOnly("EdgeOnly",Float) = 1.0
_EdgeColor("EdgeColor",Color) = (1,1,1,1)
_BackgroundColor("BackgroundColor",Color) = (1,1,1,1)
_SampleDistance("SampleDistance",Float) = 1.0
_Sensitivity("Sensitivity",Vector) = (1,1,1,1)
}
SubShader
{
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
half4 _MainTex_TexelSize;
fixed _EdgeOnly;
fixed4 _EdgeColor;
fixed4 _BackgroundColor;
float _SampleDistance;
half4 _Sensitivity;
sampler2D _CameraDepthNormalsTexture;
struct v2f
{
float4 pos:SV_POSITION;
half2 uv[5]:TEXCOORD0;
};
v2f vert(appdata_img v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
half2 uv = v.texcoord;
o.uv[0] = uv;
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
uv.y = 1 - uv.y;
#endif
//Robert算子
o.uv[1] = uv + _MainTex_TexelSize.xy * half2(1, 1) * _SampleDistance;
o.uv[2] = uv + _MainTex_TexelSize.xy * half2(-1, -1) * _SampleDistance;
o.uv[3] = uv + _MainTex_TexelSize.xy * half2(-1, 1) * _SampleDistance;
o.uv[4] = uv + _MainTex_TexelSize.xy * half2(1, -1) * _SampleDistance;
return o;
}
half CheckSame(half4 center, half4 sample)
{
half2 centerNormal = center.xy;
half centerDepth = DecodeFloatRG(center.zw);
half2 sampleNormal = sample.xy;
float sampleDepth = DecodeFloatRG(sample.zw);
half2 diffNormal = abs(centerNormal - sampleNormal) * _Sensitivity.x;
int isSameNormal = (diffNormal.x + diffNormal.y) < 0.1;
float diffDepth = abs(centerDepth - sampleDepth) * _Sensitivity.y;
int isSameDepth = diffDepth < 0.1 * centerDepth;
return isSameNormal * isSameDepth ? 1.0 : 0;
}
fixed4 frag(v2f i) :SV_Target
{
half4 sample1 = tex2D(_CameraDepthNormalsTexture, i.uv[1]);
half4 sample2 = tex2D(_CameraDepthNormalsTexture, i.uv[3]);
half4 sample3 = tex2D(_CameraDepthNormalsTexture, i.uv[3]);
half4 sample4 = tex2D(_CameraDepthNormalsTexture, i.uv[4]);
half edge = 1;
edge *= CheckSame(sample1,sample2);
edge *= CheckSame(sample3,sample4);
fixed4 withEdgeColor = lerp(_EdgeColor,tex2D(_MainTex,i.uv[0]),edge);
fixed4 onlyEdgeColor = lerp(_EdgeColor,_BackgroundColor,edge);
return lerp(withEdgeColor,onlyEdgeColor,_EdgeOnly);
}
ENDCG
Pass
{
ZTest Always Cull Off ZWrite Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDCG
}
}
}