ScreenSpaceShadowMask Blur推荐
2017-03-06 17:58
225 查看
在移动游戏中渲染阴影时,我们通常使用低分辨率的ShadowMap来降低内存,其不足之处就是锯齿明显。对此,我们推荐大家使用Unity ScreenSpaceShadowMask Blur技术来增加阴影质量,消除锯齿感。
目的
Unity自带的阴影功能ShadowMap占用内存过大,1024 * 1024占用8MB。而我们项目内存吃紧,所以只能选用512 * 512,如下图,带有明显的锯齿感,效果差了很多。如果您也有类似的需求,这时就可以采用 Unity ScreenSpaceShadowMask 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复杂度,又可以合并Draw Call。2.正常Pass就是正常渲染阴影,比较ShadowMap与自己的深度值。我们将ShadowCamera清屏色设置成黑色,最终效果为有阴影的地方有颜色,其余地方为黑色。(颜色值会当成最后的Alpha值来处理)。3.Blur Pass可以用CommandBuffer,也可以用OnPostRender。输入参数为ShaderCamera的Rendertarget,通过Blit来进行高斯模糊。(建议尽量少用CommandBuffer。我采用CommandBuffer,在小米1s上 RT->blurRT->RT会出现抖动现象,OnPostRender并没有。但是这两者原理应该是一样的,通过GPA查看,代码都是一样的。暂时不清楚其原因,欢迎有兴趣的朋友和我交流)。4.Main Camera Pass 正常渲染场景。原则上渲染的物体是不会接收阴影的。5.全屏可以通过CommandBuffer,也可以通过OnPostRender来处理。输入参数为上次经过模糊的RT值。Alpha、阴影颜色、透明度这些参数值自己写两个进行调节即可。最终渲染流程:消耗统计
1. 内存消耗(1) ShadowMap:512*512 2MB(2) ShadowCamera RT 1/4屏 带16位深度(3) Blur RT 1/4屏 不带深度这是小米4c上的数据。2. 渲染消耗统计(1)多一个相机投射阴影体,接收阴影体多渲染一次;(2)2次Blur操作;(3)1次全屏blit操作;主要对于带宽影响较大的物体影响较重。总结
1.CommandBuffer 更自由,比如很多点都可以插入自定义行为,比如对ShadowMap进行操作等。虽然稳定性不佳,性能还是可以的。2.如果一个Camera被设成RT,它会在其他相机渲染之前渲染,不受Depth影响。相应资源
1.ShadowPass ShaderShader "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. 高斯模糊Shader3. 全屏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++; // } //} }2.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 ScreenSpaceShadowMask Blur
- 稳扎稳打Silverlight(38) - 3.0滤镜之BlurEffect, DropShadowEffect, 自定义滤镜, 3D效果之PlaneProjection, 位图API之WriteableBitmap
- Screen Space Reflection
- Distance Shadowmask
- 表扩展失败(ORA-01653)后的空间管理问题【THE SPACE MANAGEMENT PROBLEM OF THE TABLE EXTEND FAILD 】 推荐
- Screen Space Reflections in Unity 5
- [gpu pro]screen space soft shadows
- TSSAO Temporal Screen-Space Ambient Occlusion (Unity3d 5 示例实现)
- 稳扎稳打Silverlight(38) - 3.0滤镜之BlurEffect, DropShadowEffect, 自定义滤镜
- Screen Space Ambient Occlusion
- 通过screen实现近乎并发的shell远程调用 思考和部分实现 推荐
- BlurMaskFilter介绍
- 在Unity中实现屏幕空间反射Screen Space Reflection(3)
- Distorting Object Shapes in Screen Space(屏幕空间扭曲)
- Screen-Space Bent Cones (SSBC) in Unity5
- Screen Space Ambient Occlusion(SSAO)
- Screen Space Soft Shadows
- UGUI Screen Space-Camera 模式 中 Animation 出现的Bug
- Unity3D图像后处理特效——Screen Space Ambient Occlusion (SSAO) image effect
- Screen-Space Bent Cones (SSBC) in Unity5