Unity3D NGUI动态生成模糊背景图
先上效果。
制作原理:模糊的部分是用UITexture,前面是一个UISprite。用主摄像机渲染出一张纹理,把这张纹理模糊处理,把这张纹理赋值给UITexture。
脚本代码
using UnityEngine; using System.Collections; [RequireComponent(typeof(UITexture))] public class BlurTextureMaker : MonoBehaviour { public int iterations = 3; public float blurSpread = 0.6f; public Shader blurShader = null; static Material m_Material = null; public Camera camera; private UITexture mTexture; private RenderTexture mRT; protected Material material { get { if (m_Material == null) { m_Material = new Material(blurShader); m_Material.hideFlags = HideFlags.DontSave; } return m_Material; } } protected void Awake() { mTexture = GetComponent<UITexture>(); } protected void Start() { // Disable if we don't support image effects if (!SystemInfo.supportsImageEffects) { enabled = false; return; } // Disable if the shader can't run on the users graphics card if (!blurShader || !material.shader.isSupported) { enabled = false; return; } int rtWidth = (int)(NGUITools.screenSize.x / 4); int rtHeight = (int)(NGUITools.screenSize.y / 4); mRT = RenderTexture.GetTemporary(rtWidth, rtHeight, 0, RenderTextureFormat.Default); mTexture.mainTexture = Generate(); } protected void OnDestroy() { if (null != mRT) { RenderTexture.ReleaseTemporary(mRT); } } // Performs one blur iteration. public void FourTapCone(RenderTexture source, RenderTexture dest, int iteration) { float off = 0.5f + iteration * blurSpread; Graphics.BlitMultiTap(source, dest, material, new Vector2(-off, -off), new Vector2(-off, off), new Vector2(off, off), new Vector2(off, -off) ); } // Downsamples the texture to a quarter resolution. private void DownSample4x(RenderTexture source, RenderTexture dest) { float off = 1.0f; Graphics.BlitMultiTap(source, dest, material, new Vector2(-off, -off), new Vector2(-off, off), new Vector2(off, off), new Vector2(off, -off) ); } // Called by the camera to apply the image effect void RenderImage(RenderTexture source, RenderTexture destination) { int rtW = source.width / 4; int rtH = source.height / 4; RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH, 0); // Copy source to the 4x4 smaller texture. DownSample4x(source, buffer); // Blur the small texture for (int i = 0; i < iterations; i++) { RenderTexture buffer2 = RenderTexture.GetTemporary(rtW, rtH, 0); FourTapCone(buffer, buffer2, i); RenderTexture.ReleaseTemporary(buffer); buffer = buffer2; } Graphics.Blit(buffer, destination); RenderTexture.ReleaseTemporary(buffer); } public RenderTexture Generate() { int rtWidth = (int) (NGUITools.screenSize.x/4); int rtHeight = (int) (NGUITools.screenSize.y/4); var tex = RenderTexture.GetTemporary(rtWidth, rtHeight, 0, RenderTextureFormat.Default); camera.targetTexture = tex; camera.Render(); camera.targetTexture = null; RenderImage(tex, mRT); RenderTexture.ReleaseTemporary(tex); return mRT; } [ContextMenu("Sample")] public void Sample() { var tex = GetComponent<UITexture>(); tex.mainTexture = Generate(); } }
//Shader代码
Shader "Hidden/BlurEffectConeTap" { Properties { _MainTex ("", any) = "" {} } SubShader { Pass { ZTest Always Cull Off ZWrite Off Fog { Mode Off } SetTexture [_MainTex] {constantColor (0,0,0,0.25) combine texture * constant alpha} SetTexture [_MainTex] {constantColor (0,0,0,0.25) combine texture * constant + previous} SetTexture [_MainTex] {constantColor (0,0,0,0.25) combine texture * constant + previous} SetTexture [_MainTex] {constantColor (0,0,0,0.25) combine texture * constant + previous} } } CGINCLUDE #include "UnityCG.cginc" struct v2f { float4 pos : SV_POSITION; half2 uv : TEXCOORD0; half2 taps[4] : TEXCOORD1; }; sampler2D _MainTex; half4 _MainTex_TexelSize; half4 _BlurOffsets; v2f vert( appdata_img v ) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord - _BlurOffsets.xy * _MainTex_TexelSize.xy; // hack, see BlurEffect.cs for the reason for this. let's make a new blur effect soon o.taps[0] = o.uv + _MainTex_TexelSize * _BlurOffsets.xy; o.taps[1] = o.uv - _MainTex_TexelSize * _BlurOffsets.xy; o.taps[2] = o.uv + _MainTex_TexelSize * _BlurOffsets.xy * half2(1,-1); o.taps[3] = o.uv - _MainTex_TexelSize * _BlurOffsets.xy * half2(1,-1); return o; } half4 frag(v2f i) : SV_Target { half4 color = tex2D(_MainTex, i.taps[0]); color += tex2D(_MainTex, i.taps[1]); color += tex2D(_MainTex, i.taps[2]); color += tex2D(_MainTex, i.taps[3]); return color * 0.25; } ENDCG SubShader { Pass { ZTest Always Cull Off ZWrite Off Fog { Mode off } CGPROGRAM #pragma fragmentoption ARB_precision_hint_fastest #pragma vertex vert #pragma fragment frag ENDCG } } Fallback off }