Unity ScreenSpaceShadowMask Blur

原创 2016年08月29日 18:28:07
一。目的
Unity自带的阴影功能 shadowmap占用内存过大。1024 * 1024占用8M。而我们项目内存吃紧。所以只能选用512 *512.而效果就差很多。
有明显锯齿。所以需要采用 screen space shadow blur。就是在屏幕空间里对已经投射完阴影的物体进行高斯模糊来增加阴影质量,减少锯齿感。(PS unity提供的软阴影应该是PCF。但是效果并不明显)。

经过 ScreenSpaceShadowMask Blur后

二。实现步骤
一.渲染流程
shadowcamera 的 shadowPass ->shadowcamera 正常pass ->blurPass ->main camera Pass ->全屏片
二。详细分析
1.shadowPass 主要产生shadowMap 只需让shadowCamera能看到投射阴影和接收阴影的物体同时把那些阴影开关打开unity会自动加入该pass.(Ps 如果物体是自己写的Vertext Fragement shader需要自己加入 shadow caster pass.调用unity内置即可。文件在 UnityStandardShadow.cginc里)
(shadow camera 在渲染前统一替换成一个简单的shader,只需包含投射跟接收阴影2个pass即可。即可以减少shader复杂度,又可以合并drawcall)
2.正常Pass 就是正常渲染阴影,比较shadowmap与自己的深度值。shadowcamera清屏色设置成黑色。最终效果为有阴影的地方有颜色,其余地方为黑色。(颜色值会当成最后的alpha值来处理)。

3.blur Pass
可以用commadnbuffer 也可以用OnPostRender。输入参数为shadercamera的 rendertarget。通过blit来进行高斯模糊。(建议能不用commandbuffer就不用commandbuffer。我采用commandbuffer,在小米1s上 RT->blurRT->RT会出现抖动现象,OnPostRender并没有。但是这两者原理应该是一样的,通过GPA查看,代码都是一样的。不知道为什么了。)
4.main camera pass 正常渲染场景。原则上渲染的物体没有接收阴影的。
5.全屏片 可以通过commandbuffer 也可以通过 OnPostRender。输入参数为上次经过模糊的RT的值当alpha,阴影颜色 透明度自己写两个参数进行调节即可。最终渲染流程

三。消耗
1.内存消耗
shadowmap 512 *512 2M
shadow camera RT 1/4屏 带16位深度
blur RT 1/4屏 不带深度
这是4c数据。

2.渲染消耗
多一个相机 投射阴影体,接收阴影体多渲染一次
2次blur操作。
1次全屏blit操作。
主要对于带宽影响较大的物体影响较重。
四。总结
1.commandbuffer 更自由,比如很多点都可以插自定义行为,比如对shadowmap进行操作等。但是稳定性不佳。性能Ok。
2.如果一个camera被设成成RT,他会在其他相机渲染之前渲染,不受depth影响。
五。相应资源
1.shadowPass shader

Shader "Shadow/ShadowMask" {
Properties
{
}
SubShader
{
Tags { "RenderType"="Geometry" }
Pass
{
Tags {"LightMode"="ForwardBase"}
CGPROGRAM
#pragma multi_compile_fwdbase
#pragma vertex vertForwardBase
#pragma fragment fragForwardBase
struct appdata_input
{
float4 vertex : POSITION;
};

struct v2f
{
float4 pos : SV_POSITION;
LIGHTING_COORDS(1,2)
};

v2f vertForwardBase (appdata_input v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
TRANSFER_VERTEX_TO_FRAGMENT(o);
return o;
}

fixed4 fragForwardBase (v2f i) : SV_Target
{
fixed4 col = fixed4(1,0,0,1);
fixed attenuation = LIGHT_ATTENUATION(i);
col = col * (1-attenuation);
return col;
}
ENDCG
}
Pass
{
Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
Fog {Mode Off}
ZWrite On ZTest LEqual Cull Off
Offset 1, 1
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct v2f {
V2F_SHADOW_CASTER;
};
v2f vert( appdata_base v )
{
v2f o;
TRANSFER_SHADOW_CASTER(o)
return o;
}
float4 frag( v2f i ) : COLOR
{
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
}
}
2. 高斯模糊shader 就很普通的高斯模糊shader
3.全屏blit shader
Shader "BlitQuad1"
{
Properties
{
_MainTex("MainTexture",2D) = "white"{}
_Color("ShadowColor",Color) = (0,0,0,1)
_Intension("Intension",Float) = 0.6
}
SubShader
{
Tags { "RenderType"="Transparent" }

Blend SrcAlpha OneMinusSrcAlpha
zwrite off

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};

struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};

sampler2D _MainTex;
half4 _MainTex_TexelSize;
float _Intension;
fixed _Color;
v2f vert (appdata v)
{
v2f o;
o.vertex = v.vertex;
o.uv = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
half4 color = half4(1,1,1,1) * _Color;
half4 alpha = tex2D(_MainTex,i.uv);
color.a = alpha.r * _Intension;
return color;
}
ENDCG
}
}
}
C#脚本
1。shadowCamera 挂载实现 注释代码为commandbuffer
using UnityEngine;
using UnityEngine.Rendering;
using System.Collections;

public class ShadowMask : MonoBehaviour
{
//public int maxBlurCount = 2;
public int sampleOffset = 2;

private const float UIWIDTH = 1136f;
private const int MAX_VALUE = 2048;
private int screenWidth;
private int screenHeight;

public RenderTexture renderTexture;
public RenderTexture blurRT;

//private RenderTargetIdentifier rtl;
//private RenderTargetIdentifier blurRtl;

//private CommandBuffer blurCommand;
//private CommandBuffer screenQuadCommand;

private Material material1;
private Material material2;

public Camera shadowCamera;
//public Camera mainCamera;

private int SCALE = 2;

//private int pass = 0;
//private bool hasAdd = false;

void Awake()
{
RenderTextureFormateSupportTool.GetInstance().Init();

screenWidth = Mathf.Min(Screen.width, MAX_VALUE);
screenHeight = Mathf.Min(Screen.height, MAX_VALUE);

renderTexture = RenderTextureFormateSupportTool.GetInstance().GetRenderTexture(screenWidth / SCALE, screenHeight / SCALE, 16, RenderTextureFormateSupportTool.H3DRenderTextureFormate.R8);

renderTexture.name = "RenderTexture";

blurRT = RenderTextureFormateSupportTool.GetInstance().GetRenderTexture(screenWidth / SCALE, screenHeight / SCALE,0, RenderTextureFormateSupportTool.H3DRenderTextureFormate.R8);

blurRT.name = "BlurRT";

float aspectValue = shadowCamera.aspect;
shadowCamera.targetTexture = renderTexture;
shadowCamera.aspect = aspectValue;


Shader shadowShader = Shader.Find("Shadow/ShadowMask");
shadowCamera.SetReplacementShader(shadowShader, "");

//blurCommand = new CommandBuffer();
//blurCommand.name = "BlurShadowMask";

//screenQuadCommand = new CommandBuffer();
//screenQuadCommand.name = "ScreenQuad";

//rtl = new RenderTargetIdentifier(renderTexture);
//blurRtl = new RenderTargetIdentifier(blurRT);
Shader blurShader = Shader.Find("Shadow/ShadowMaskBlur");
material1 = new Material(blurShader);
material2 = new Material(blurShader);
}

void OnPostRender()
{
material1.SetTexture("_MainTexture", renderTexture);
material1.SetInt("_Horizontal", 0);
material1.SetInt("_SampleOffset", sampleOffset);
Graphics.Blit(renderTexture, blurRT, material1);


material2.SetTexture("_MainTexture", blurRT);
material2.SetInt("_Horizontal", 1);
material2.SetInt("_SampleOffset", sampleOffset);
Graphics.Blit(blurRT, renderTexture, material2);
}

//void Update()
//{
// if (hasAdd)
// {
// blurCommand.Clear();
// }
// else
// {
// shadowCamera.AddCommandBuffer(CameraEvent.AfterEverything, blurCommand);
// hasAdd = true;
// }

// for (int i = 0; i < maxBlurCount; i++)
// {
// if (i % 2 == 0)
// {
// material1.SetTexture("_MainTexture", renderTexture);
// material1.SetInt("_Horizontal", pass % 2);
// material1.SetInt("_SampleOffset", sampleOffset);
// blurCommand.Blit(rtl, blurRtl, material1);
// }
// else
// {
// material2.SetTexture("_MainTexture", blurRT);
// material2.SetInt("_Horizontal", pass % 2);
// material2.SetInt("_SampleOffset", sampleOffset);
// blurCommand.Blit(blurRtl, blurRt2, material2);
// }
// pass++;
// }
//}
}
3.mainCamera挂载实现 全屏blit操作
using UnityEngine;
using System.Collections;

public class MainCameraTest : MonoBehaviour
{

public ShadowMask shadowMask;
public float shadowIntensity = 1f;
public Color shadowColor = Color.black;


private Material screenQuadMaterial;
private Mesh screenQuadMesh;
private Matrix4x4 matrix;
public void Start()
{
Shader screenQuadShader = Shader.Find("BlitQuad");
screenQuadMaterial = new Material(screenQuadShader);
screenQuadMaterial.SetTexture("_MainTex", shadowMask.renderTexture);

screenQuadMesh = new Mesh();
Vector3[] verts = new Vector3[4];
verts[0] = new Vector3(-1, -1, 0);
verts[1] = new Vector3(-1, 1, 0);
verts[2] = new Vector3(1, 1, 0);
verts[3] = new Vector3(1, -1, 0);
screenQuadMesh.vertices = verts;
Vector2[] uvs = new Vector2[4];
uvs[0] = new Vector2(0, 0);
uvs[1] = new Vector2(0, 1);
uvs[2] = new Vector2(1, 1);
uvs[3] = new Vector2(1, 0);
screenQuadMesh.uv = uvs;

int[] indices = new int[6];
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;

indices[3] = 0;
indices[4] = 2;
indices[5] = 3;
screenQuadMesh.triangles = indices;

screenQuadMesh.Optimize();

matrix = Matrix4x4.identity;

}

void OnPostRender()
{
screenQuadMaterial.SetFloat("_Intension", shadowIntensity);
screenQuadMaterial.SetColor("_Color", shadowColor);
screenQuadMaterial.SetPass(0);
Graphics.DrawMeshNow(screenQuadMesh, matrix);
}
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

【Unity Shader编程】之十五 屏幕高斯模糊(Gaussian Blur)后期特效的实现

本系列文章由@浅墨_毛星云 出品,转载请注明出处。   文章链接: http://blog.csdn.net/poem_qianmo/article/details/51871531 作者:毛星云...
  • aasd1m
  • aasd1m
  • 2016年12月07日 16:22
  • 103

Unity Shader编程】之十五 屏幕高斯模糊(Gaussian Blur)后期特效的实现

本篇文章将分析如何在unity中基于Shader实现高斯模糊屏幕后期特效。 首先放出最终的实现效果。如下几幅图,是在Unity中使用本文所实现的Shader得到的高斯模糊屏幕后期特效与原始图的效果对...

Unity3D图像后处理特效——Motion Blur image effect

Motion Blur image effect enhances fast-moving scenes by leaving "motion trails" of previously render...

Unity3D图像后处理特效——Blur image effect

The Blur image effect blurs the rendered image in real-time. 模糊图像特效实时地模糊所渲染出的图像。   As with the...

Unity3D 背景动态模糊(blur)和截屏方法

unity 提供了一个函数 OnRenderImage (RenderTexture source, RenderTexture destination) ,只要将这个组件挂载在Camera上面。就能...

【Unity Shader编程】之十五 屏幕高斯模糊(Gaussian Blur)后期特效的实现

本篇文章将分析如何在Unity中基于Shader实现高斯模糊屏幕后期特效。 首先放出最终的实现效果。如下几幅图,是在Unity中使用本文所实现的Shader得到的高斯模糊屏幕后期特效与原始图的效果...
  • zhmxy555
  • zhmxy555
  • 2016年07月10日 15:51
  • 36140

blur后滾動條的變化

  • 2007年12月10日 11:26
  • 35KB
  • 下载

【OpenCV_09】平滑/模糊图片 Smooth / Blur Images及 彩色图转 灰度图和二值化

这一节,谈一谈如何对图像进行平滑,也可以叫做模糊。平滑图像的主要目的是减少噪声,这样采用平滑图像来降低噪声是是非常常见的预处理方法。 1.归一化滤波平滑-Homogeneous Smoothing ...
  • tealex
  • tealex
  • 2016年06月01日 10:02
  • 2316

Android blur模糊

  • 2015年08月07日 15:18
  • 2.36MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Unity ScreenSpaceShadowMask Blur
举报原因:
原因补充:

(最多只允许输入30个字)