Unity后处理实现物体外描边
来源:互联网 发布:淘宝买书有什么好店铺 编辑:程序博客网 时间:2024/06/06 01:54
效果
原理
使用后处理,
- 在后处理阶段先渲染产生一张RenderTexture,包含要被描边的物体,使用描边色渲染。
- 高斯模糊RenderTexture,会产生边缘
- 用高斯模糊的图片反向剔除未模糊的图,这样只保留模糊多出的部分。
- 此时RenderTexture上为只有边缘的图,将此边缘图与渲染结果图进行混合并输出屏幕,即得到结果。
实现
OutLineCameraComponent.cs 挂载在摄像机下,赋值两个shader。
using UnityEngine; using System.Collections.Generic;using UnityEngine.Rendering; [ExecuteInEditMode]public class OutLineCameraComponent{ private RenderTexture renderTexture = null; private CommandBuffer commandBuffer = null; [Header("Outline/OutLineEffect.shader")] public Shader preoutlineShader = null; [Header("Outline/OutlinePrePass.shader")] public Shader shader = null; private Material _material = null; public Material mMaterial { get { if (_material == null) _material = GenerateMaterial(shader); return _material; } } [Header("采样范围")] public float samplerArea = 1; [Header("降分辨率")] public int downSample = 1; [Header("迭代次数")] public int iteration = 2; [Header("描边强度")] [Range(0.0f, 10.0f)] public float outLineStrength = 3.0f; //根据shader创建用于屏幕特效的材质 protected Material GenerateMaterial(Shader shader) { if (shader == null) return null; if (shader.isSupported == false) return null; Material material = new Material(shader); material.hideFlags = HideFlags.DontSave; if (material) return material; return null; } //目标对象 private List<OutLineTargetComponent> targetObjects = new List<OutLineTargetComponent>(); public void AddTarget(OutLineTargetComponent target) { if(target.material==null) target.material = new Material(preoutlineShader); targetObjects.Add(target); RefreshCommandBuff(); } public void RemoveTarget(OutLineTargetComponent target) { bool found = false; for (int i = 0; i < targetObjects.Count; i++) { if (targetObjects[i] == target) { targetObjects.Remove(target); DestroyImmediate(target.material); target.material = null; found = true; break; } } if(found) RefreshCommandBuff(); } public void RefreshCommandBuff() { if (renderTexture) RenderTexture.ReleaseTemporary(renderTexture); renderTexture = RenderTexture.GetTemporary(Screen.width >> downSample, Screen.height >> downSample, 0); commandBuffer = new CommandBuffer(); commandBuffer.SetRenderTarget(renderTexture); commandBuffer.ClearRenderTarget(true, true, Color.black); for (int i = 0; i < targetObjects.Count; i++) { Renderer[] renderers = targetObjects[i].GetComponentsInChildren<Renderer>(); foreach (Renderer r in renderers) commandBuffer.DrawRenderer(r, targetObjects[i].material); } } void OnEnable() { if (preoutlineShader == null) return; RefreshCommandBuff(); } void OnDisable() { if (renderTexture) { RenderTexture.ReleaseTemporary(renderTexture); renderTexture = null; } if (commandBuffer != null) { commandBuffer.Release(); commandBuffer = null; } } void OnRenderImage(RenderTexture source, RenderTexture destination) { if (mMaterial && renderTexture && commandBuffer != null) { Graphics.ExecuteCommandBuffer(commandBuffer); //对RT进行Blur处理 RenderTexture temp1 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0); RenderTexture temp2 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0); //高斯模糊,两次模糊,横向纵向,使用pass0进行高斯模糊 mMaterial.SetVector("_offsets", new Vector4(0, samplerArea, 0, 0)); Graphics.Blit(renderTexture, temp1, mMaterial, 0); mMaterial.SetVector("_offsets", new Vector4(samplerArea, 0, 0, 0)); Graphics.Blit(temp1, temp2, mMaterial, 0); //如果有叠加再进行迭代模糊处理 for(int i = 0; i < iteration; i++) { mMaterial.SetVector("_offsets", new Vector4(0, samplerArea, 0, 0)); Graphics.Blit(temp2, temp1, mMaterial, 0); mMaterial.SetVector("_offsets", new Vector4(samplerArea, 0, 0, 0)); Graphics.Blit(temp1, temp2, mMaterial, 0); } //用模糊图和原始图计算出轮廓图 mMaterial.SetTexture("_BlurTex", temp2); Graphics.Blit(renderTexture, temp1, mMaterial, 1); //轮廓图和场景图叠加 mMaterial.SetTexture("_BlurTex", temp1); mMaterial.SetFloat("_OutlineStrength", outLineStrength); Graphics.Blit(source, destination, mMaterial, 2); RenderTexture.ReleaseTemporary(temp1); RenderTexture.ReleaseTemporary(temp2); } else { Graphics.Blit(source, destination); } } }
OutLineTargetComponent.cs 挂载在要使用描边的物体上
using UnityEngine;[ExecuteInEditMode]public class OutLineTargetComponent : MonoBehaviour{ public Color color = Color.green; public Material material { set; get; } void OnEnable() { Camera[] allCameras = Camera.allCameras; for (int i = 0; i < allCameras.Length; i++) { if (allCameras[i].GetComponent<OutLineCameraComponent>()!=null) { allCameras[i].GetComponent<OutLineCameraComponent>().AddTarget(this); } } } private void Update() { if(material!=null) material.SetColor("_OutLineColor", color); } void OnDisable() { Camera[] allCameras = Camera.allCameras; for (int i = 0; i < allCameras.Length; i++) { if (allCameras[i].GetComponent<OutLineCameraComponent>()!=null) { allCameras[i].GetComponent<OutLineCameraComponent>().RemoveTarget(this); } } }}
OutlinePrePass.shader
Shader "OutLine/OutlinePrePass" { SubShader { Pass { CGPROGRAM #include "UnityCG.cginc" fixed4 _OutLineColor; struct v2f { float4 pos : SV_POSITION; }; v2f vert(appdata_full v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); return o; } fixed4 frag(v2f i) : SV_Target { return _OutLineColor; } #pragma vertex vert #pragma fragment frag ENDCG } } }
OutLineEffect.shader
Shader "OutLine/OutLineEffect" { Properties{ _MainTex("Base (RGB)", 2D) = "white" {} _BlurTex("Blur", 2D) = "white"{} } CGINCLUDE #include "UnityCG.cginc" //用于剔除中心留下轮廓 struct v2f_cull { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; }; //用于模糊 struct v2f_blur { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float4 uv01 : TEXCOORD1; float4 uv23 : TEXCOORD2; float4 uv45 : TEXCOORD3; }; //用于最后叠加 struct v2f_add { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; float2 uv1 : TEXCOORD1; }; sampler2D _MainTex; float4 _MainTex_TexelSize; sampler2D _BlurTex; float4 _BlurTex_TexelSize; float4 _offsets; float _OutlineStrength; //获得轮廓 pass 1 v2f_cull vert_cull(appdata_img v) { v2f_cull o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord.xy; //dx中纹理从左上角为初始坐标,需要反向 #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) o.uv.y = 1 - o.uv.y; #endif return o; } fixed4 frag_cull(v2f_cull i) : SV_Target { fixed4 colorMain = tex2D(_MainTex, i.uv); fixed4 colorBlur = tex2D(_BlurTex, i.uv); return colorBlur - colorMain; } //高斯模糊 pass 0 v2f_blur vert_blur(appdata_img v) { v2f_blur o; _offsets *= _MainTex_TexelSize.xyxy; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord.xy; o.uv01 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1); o.uv23 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 2.0; o.uv45 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 3.0; return o; } fixed4 frag_blur(v2f_blur i) : SV_Target { fixed4 color = fixed4(0,0,0,0); color += 0.40 * tex2D(_MainTex, i.uv); color += 0.15 * tex2D(_MainTex, i.uv01.xy); color += 0.15 * tex2D(_MainTex, i.uv01.zw); color += 0.10 * tex2D(_MainTex, i.uv23.xy); color += 0.10 * tex2D(_MainTex, i.uv23.zw); color += 0.05 * tex2D(_MainTex, i.uv45.xy); color += 0.05 * tex2D(_MainTex, i.uv45.zw); return color; } //最终叠加 pass 2 v2f_add vert_final(appdata_img v) { v2f_add o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv.xy = v.texcoord.xy; o.uv1.xy = o.uv.xy; #if UNITY_UV_STARTS_AT_TOP if (_MainTex_TexelSize.y < 0) o.uv.y = 1 - o.uv.y; #endif return o; } fixed4 frag_final(v2f_add i) : SV_Target { fixed4 ori = tex2D(_MainTex, i.uv1); fixed4 blur = tex2D(_BlurTex, i.uv); fixed4 final = ori + blur * _OutlineStrength; return final; } ENDCG SubShader { //pass 0: 高斯模糊 Pass { ZTest Off Cull Off ZWrite Off Fog{ Mode Off } CGPROGRAM #pragma vertex vert_blur #pragma fragment frag_blur ENDCG } //pass 1: 剔除中心部分 Pass { ZTest Off Cull Off ZWrite Off Fog{ Mode Off } CGPROGRAM #pragma vertex vert_cull #pragma fragment frag_cull ENDCG } //pass 2: 最终叠加 Pass { ZTest Off Cull Off ZWrite Off Fog{ Mode Off } CGPROGRAM #pragma vertex vert_final #pragma fragment frag_final ENDCG } } }
阅读全文
0 0
- Unity后处理实现物体外描边
- unity透明物体处理
- Unity 实现点击物体
- unity实现3D物体上的事件监听处理
- Unity-->实现物体的移动
- Unity实现物体逐渐消失
- Unity 模拟爆炸后的物体碰撞
- unity 学习 处理一个物体 单击事件
- Unity通过脚本实现给一个物体添加子物体
- Unity中实现3D物体跳跃
- Unity 点击Terrian实现物体移动
- Unity 实现鼠标拖动3D物体
- unity 协程 实现物体颜色动态切换
- Unity中物体抛物线的实现方式
- Unity中物体抛物线的实现
- unity实现鼠标点击后拖拽物体
- unity实现第三视角跟随物体运动
- Unity物体跟随鼠标的实现
- epoll实现简单echo服务器
- Jenkins check-out strategy
- 关于两个APP之间的跳转实现手机联系人展示
- 关于ajax提交表单的问题
- centos下mysql配置
- Unity后处理实现物体外描边
- nginx 部署angular项目
- NFS服务器不能挂载问题终极解决办法
- 发送定长宝解决网络粘包问题
- Netty学习笔记12——编解码器框架
- could not be set to a 'string' value. You must set this property to a non-null value of type
- Oracle中connect,resource角色权限
- 判断一个节点是否在一棵二叉树中&&判断一颗二叉树是是否是另一颗树的子树
- 设备管理器