【Unity ImageEffect】一个用于角色外边缘发光的效果
2016-01-14 10:17
615 查看
前言
现在很多游戏都有选中角色后高亮显示选中目标的需求,但是Unity是没有提供这样的功能(很不爽)。虽然在Unity Store上有几款很不错的插件能满足需求,但是往往别人的东西过于复杂或者不够定制化,有些时候还是不如自己开发的好。在网上能搜索出几篇零零散散的文章有说如何实现,再结合分析了一个插件的原理后,自己边写了一个外边缘发光的镜头效果。方案
原理跟大众一致,分为如下步骤:渲染一张需要外发光的角色模板纹理
把这张纹理进行斜上下左右偏移,存为另外一张纹理
将偏移纹理进行模糊处理
用模糊纹理跟模板纹理进行像素比对
实现
效果Blur.shader代码
Shader "Yogi/ImageEffect/Blur" { Properties { _MainTex("Base (RGB)", 2D) = "white" {} _Offset("Offset", Vector) = (0, 0, 0, 0) } SubShader { Pass { ZTest Always ZWrite Off Cull Off Fog{ Mode Off } CGPROGRAM #include "UnityCG.cginc" #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest sampler2D _MainTex; fixed2 _Offset; struct a2v { fixed4 vertex : POSITION; fixed2 texcoord : TEXCOORD0; }; struct v2f { fixed4 vertex : SV_POSITION; fixed2 uv : TEXCOORD0; fixed2 offsets[4] : TEXCOORD1; }; v2f vert(a2v v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord.xy; o.offsets[0] = fixed2(_Offset.x, _Offset.y); o.offsets[1] = fixed2(-_Offset.x, _Offset.y); o.offsets[2] = fixed2(_Offset.x, -_Offset.y); o.offsets[3] = fixed2(-_Offset.x, -_Offset.y); return o; } fixed4 frag(v2f i) : SV_Target { fixed4 o = tex2D(_MainTex, i.uv); o += tex2D(_MainTex, i.uv + i.offsets[0]); o += tex2D(_MainTex, i.uv + i.offsets[1]); o += tex2D(_MainTex, i.uv + i.offsets[2]); o += tex2D(_MainTex, i.uv + i.offsets[3]); o *= 0.2f; return o; } ENDCG } } Fallback off }
Outline.shader代码
Shader "Yogi/ImageEffect/Outline" { Properties { _MainTex("Base (RGB)", 2D) = "white" {} _StencilMap("StencilMap (RGB)", 2D) = "white" {} _BlurMap("BlurMap (RGB)", 2D) = "white" {} _OutlineColor("Outline Color", Color) = (1, 1, 1, 1) _Intensity("Intensity", Float) = 1 } SubShader { Pass { ZTest Always ZWrite Off Cull Off Fog{ Mode Off } CGPROGRAM #include "UnityCG.cginc" #pragma vertex vert #pragma fragment frag #pragma fragmentoption ARB_precision_hint_fastest sampler2D _MainTex; sampler2D _StencilMap; sampler2D _BlurMap; fixed3 _OutlineColor; fixed _Intensity; struct a2v { fixed4 vertex : POSITION; fixed2 texcoord : TEXCOORD0; }; struct v2f { fixed4 vertex : SV_POSITION; fixed2 uv : TEXCOORD0; }; v2f vert(a2v v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord.xy; return o; } fixed4 frag(v2f i) : SV_Target { fixed4 c = tex2D(_MainTex, i.uv); fixed4 s = tex2D(_StencilMap, i.uv); fixed4 b = tex2D(_BlurMap, i.uv); fixed4 o = b - s; o.rgb = c.rgb + saturate(o.a) * _Intensity * _OutlineColor; o.a = c.a; return o; } ENDCG } } Fallback off }
OutlineEffect.cs代码
using UnityEngine; [RequireComponent(typeof(Camera))] [ExecuteInEditMode] public class OutlineEffect : MonoBehaviour { private const string NODE = "Outline Camera"; [Range(0.1f, 1.0f)] public float sample = 0.25f; [Range(0.0f, 1.0f)] public float spread = 0.5f; [Range(0, 4)] public int iteration = 2; [Range(0.0f, 10.0f)] public float intensity = 1.0f; public Color outlineColor = Color.white; public LayerMask cullingMask; private Camera outlineCamera { get { if (null == m_OutlineCamera) { Transform node = transform.FindChild(NODE); if (null == node) { node = new GameObject(NODE).transform; node.parent = transform; node.localPosition = Vector3.zero; node.localRotation = Quaternion.identity; node.localScale = Vector3.one; } m_OutlineCamera = node.GetComponent<Camera>(); if (null == m_OutlineCamera) { m_OutlineCamera = node.gameObject.AddComponent<Camera>(); } m_OutlineCamera.enabled = false; m_OutlineCamera.clearFlags = CameraClearFlags.SolidColor; m_OutlineCamera.backgroundColor = new Color(0, 0, 0, 0); m_OutlineCamera.renderingPath = RenderingPath.VertexLit; m_OutlineCamera.hdr = false; m_OutlineCamera.useOcclusionCulling = false; m_OutlineCamera.gameObject.hideFlags = HideFlags.HideAndDontSave; } return m_OutlineCamera; } } private Camera m_OutlineCamera; private Material outlineMaterial { get { if (m_OutlineMaterial == null) { m_OutlineMaterial = new Material(Shader.Find("Yogi/ImageEffect/Outline")); m_OutlineMaterial.hideFlags = HideFlags.HideAndDontSave; } return m_OutlineMaterial; } } private Material m_OutlineMaterial = null; private Material blurMaterial { get { if (m_BlurMaterial == null) { m_BlurMaterial = new Material(Shader.Find("Yogi/ImageEffect/Blur")); m_BlurMaterial.hideFlags = HideFlags.HideAndDontSave; } return m_BlurMaterial; } } private Material m_BlurMaterial = null; private RenderTexture stencilMap; private void OnPreRender() { stencilMap = RenderTexture.GetTemporary(Screen.width, Screen.height, 0); outlineCamera.fieldOfView = camera.fieldOfView; outlineCamera.isOrthoGraphic = camera.isOrthoGraphic; outlineCamera.nearClipPlane = camera.nearClipPlane; outlineCamera.farClipPlane = camera.farClipPlane; outlineCamera.cullingMask = cullingMask; outlineCamera.targetTexture = stencilMap; outlineCamera.Render(); } private void OnPostRender() { RenderTexture.ReleaseTemporary(stencilMap); } private void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture) { int width = (int)(sourceTexture.width * sample); int height = (int)(sourceTexture.height * sample); RenderTexture blurMap = RenderTexture.GetTemporary(width, height, 0); Graphics.Blit(stencilMap, blurMap); for (int i = 0; i < iteration; ++i) { RenderTexture buffer = RenderTexture.GetTemporary(width, height, 0); float offset = spread * i + 0.5f; blurMaterial.SetVector("_Offset", new Vector4(offset / width, offset / height)); Graphics.Blit(blurMap, buffer, blurMaterial); RenderTexture.ReleaseTemporary(blurMap); blurMap = buffer; } outlineMaterial.SetTexture("_StencilMap", stencilMap); outlineMaterial.SetTexture("_BlurMap", blurMap); outlineMaterial.SetColor("_OutlineColor", outlineColor); outlineMaterial.SetFloat("_Intensity", intensity); Graphics.Blit(sourceTexture, destTexture, outlineMaterial); RenderTexture.ReleaseTemporary(blurMap); } private void OnDisable() { OnDestroy(); } private void OnDestroy() { if (null != m_OutlineCamera) { if (Application.isPlaying) { Destroy(m_OutlineCamera.gameObject); } else { DestroyImmediate(m_OutlineCamera.gameObject); } } } }
最后
高亮效果不是每时每刻都打开的,所以还需开发者自己根据逻辑去控制开关。相关文章推荐
- Unity中私有变量如何显示在Inpsector面板中?
- 初尝用Unity3D配合Vuforia开发适合Cardboard的AR(增强现实)应用
- 构建ASP.NET MVC5+EF6+EasyUI 1.4.3+Unity4.x注入的后台管理系统(53)-工作流设计-我的批阅
- Unity Toast插件(UGUI版)
- NGUI研究之在Unity中使用贝塞尔曲线
- 【Unity】persp和iso两种模式的区别
- android Unity游戏中集成 Admob集成全屏广告教程
- Unity3D研究院之IOS本地消息通知LocalNotification的使用(六十七)
- Unity3d 综合性能窍门
- 【Unity Shader】浅析Unity shader中RenderType的作用及_CameraDepthNormalsTexture
- Unity3D游戏开发创建桌面快捷方式
- Unity3D 游戏开发构架篇 ——输入控制
- Unity 使用自定义资源(.asset)配置数据
- unity让shader支持UGUI Mask
- unity3d远程加载资源模型到本地并加载(二)第一次加载资源后写到本地后从本地加载。
- 在unity中调用某个程序运行
- unity3d 中IDropHandler 和 IEndDragHandler 优先级别
- unity, undo
- Unity中LoadLevel与LoadLevelAsync的区别
- unity3d 音频无缝循环