当前位置: 首页 > news >正文

Unity Shader-Command Buffer的使用(景深与描边效果重置版)

Unity Shader-Command Buffer的使用(景深与描边效果重置版)

https://blog.csdn.net/puppet_master/article/details/72669977

Unity Shader-后处理:时空扭曲效果

https://blog.csdn.net/puppet_master/article/details/71437031

UnityShader实例15:屏幕特效之Bloom

https://blog.csdn.net/u011047171/article/details/48522073

Unity3D Shdaer 实现镜头模糊效果[Shader]

https://blog.csdn.net/qq_28221881/article/details/54618798

unity3d 带缓冲的镜头拉近效果

https://blog.csdn.net/fzhlee/article/details/8667251

 

版权声明:欢迎转载,共同进步。请注明出处:http://blog.csdn.net/puppet_master https://blog.csdn.net/puppet_master/article/details/72669977

简介

 

Command Buffer是Unity5新增的一个灰常灰常强大的功能。先祭出官方介绍和文档。我们在渲染的时候,给OpenGL或者DX的就是一系列的指令,比如glDrawElement,glClear等等,这些东西目前是引擎去调用的,而Unity也为我们封装了更高一级的API,也就是CommandBuffer,可以让我们更加方便灵活地实现一些效果。CommandBuffer最主要的功能是可以预定义一些列的渲染指令,然后将这些指令在我们想要的时机进行执行。本篇文章简单介绍一下CommandBuffer的使用,首先实现一个简单的摄像机效果,然后通过Command Buffer重置一下之前实现过的两个效果:景深和描边效果。

 

CommandBuffer的基本用法

 

我们先来看一个最简单的例子,直接在一张RT上画个人,其实类似于摄影机效果,我们用当前的相机看见正常要看见的对象,然后在一张幕布(简单的来说,就是一个。。额,面片)再渲染一次这个人物(也可以直接渲染到UI上)。

 
  1. //Command Buffer测试

  2. //by: puppet_master

  3. //2017.5.26

  4.  
  5. using System.Collections;

  6. using System.Collections.Generic;

  7. using UnityEngine;

  8. using UnityEngine.Rendering;

  9.  
  10. public class CommandBufferTest : MonoBehaviour {

  11.  
  12. private CommandBuffer commandBuffer = null;

  13. private RenderTexture renderTexture = null;

  14. private Renderer targetRenderer = null;

  15. public GameObject targetObject = null;

  16. public Material replaceMaterial = null;

  17.  
  18. void OnEnable()

  19. {

  20. targetRenderer = targetObject.GetComponentInChildren<Renderer>();

  21. //申请RT

  22. renderTexture = RenderTexture.GetTemporary(512, 512, 16, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default, 4);

  23. commandBuffer = new CommandBuffer();

  24. //设置Command Buffer渲染目标为申请的RT

  25. commandBuffer.SetRenderTarget(renderTexture);

  26. //初始颜色设置为灰色

  27. commandBuffer.ClearRenderTarget(true, true, Color.gray);

  28. //绘制目标对象,如果没有替换材质,就用自己的材质

  29. Material mat = replaceMaterial == null ? targetRenderer.sharedMaterial : replaceMaterial;

  30. commandBuffer.DrawRenderer(targetRenderer, mat);

  31. //然后接受物体的材质使用这张RT作为主纹理

  32. this.GetComponent<Renderer>().sharedMaterial.mainTexture = renderTexture;

  33. //直接加入相机的CommandBuffer事件队列中

  34. Camera.main.AddCommandBuffer(CameraEvent.AfterForwardOpaque, commandBuffer);

  35. }

  36.  
  37. void OnDisable()

  38. {

  39. //移除事件,清理资源

  40. Camera.main.RemoveCommandBuffer(CameraEvent.AfterForwardOpaque, commandBuffer);

  41. commandBuffer.Clear();

  42. renderTexture.Release();

  43. }

  44.  
  45. //也可以在OnPreRender中直接通过Graphics执行Command Buffer,不过OnPreRender和OnPostRender只在挂在相机的脚本上才有作用!!!

  46. //void OnPreRender()

  47. //{

  48. // //在正式渲染前执行Command Buffer

  49. // Graphics.ExecuteCommandBuffer(commandBuffer);

  50. //}

  51. }

然后,我们可以把这个脚本挂在一个对象上,将要渲染的目标拖入就可以了。我们测试一下:

Command Buffer在渲染目标的时候,是支持我们使用自定义材质的,我们可以换一个材质,如果我们做了个摄像机,还不带美颜功能的话,肯定是要得差评的,所以,我们给渲染的对象换一个自定义的材质,比如边缘光效果,直接将调整好的边缘光材质球赋给Replace Material即可:

 

通过Command Buffer对RT进行后处理

 

如果感觉只是换一个材质球不够过瘾的话,我们就再发掘一下Command Buffer更深层次的功能吧!下面放大招啦!又是后处理,不过我们后处理的对象改了一下,不是基于屏幕,而是基于Command Buffer输出的那张Render Texture。比如我们稍微修改一下上面的代码,增加一个最简单的屏幕较色后处理(其实就是我比较懒罢了>_<)

 
  1. //Command Buffer测试

  2. //by: puppet_master

  3. //2017.5.26

  4.  
  5. using System.Collections;

  6. using System.Collections.Generic;

  7. using UnityEngine;

  8. using UnityEngine.Rendering;

  9.  
  10. public class CommandBufferTest : PostEffectBase {

  11.  
  12. private CommandBuffer commandBuffer = null;

  13. private RenderTexture renderTexture = null;

  14. private Renderer targetRenderer = null;

  15. public GameObject targetObject = null;

  16. public Material replaceMaterial = null;

  17.  
  18. [Range(0.0f, 3.0f)]

  19. public float brightness = 1.0f;//亮度

  20. [Range(0.0f, 3.0f)]

  21. public float contrast = 1.0f; //对比度

  22. [Range(0.0f, 3.0f)]

  23. public float saturation = 1.0f;//饱和度

  24.  
  25. void OnEnable()

  26. {

  27. targetRenderer = targetObject.GetComponentInChildren<Renderer>();

  28. //申请RT

  29. renderTexture = RenderTexture.GetTemporary(512, 512, 16, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Default, 4);

  30. commandBuffer = new CommandBuffer();

  31. //设置Command Buffer渲染目标为申请的RT

  32. commandBuffer.SetRenderTarget(renderTexture);

  33. //初始颜色设置为灰色

  34. commandBuffer.ClearRenderTarget(true, true, Color.gray);

  35. //绘制目标对象,如果没有替换材质,就用自己的材质

  36. Material mat = replaceMaterial == null ? targetRenderer.sharedMaterial : replaceMaterial;

  37. commandBuffer.DrawRenderer(targetRenderer, mat);

  38. //然后接受物体的材质使用这张RT作为主纹理

  39. this.GetComponent<Renderer>().sharedMaterial.mainTexture = renderTexture;

  40. if (_Material)

  41. {

  42. //这是个比较危险的写法,一张RT即作为输入又作为输出,在某些显卡上可能不支持,如果不像我这么懒的话...还是额外申请一张RT

  43. commandBuffer.Blit(renderTexture, renderTexture, _Material);

  44. }

  45. //直接加入相机的CommandBuffer事件队列中

  46. Camera.main.AddCommandBuffer(CameraEvent.BeforeForwardOpaque, commandBuffer);

  47. }

  48.  
  49. void OnDisable()

  50. {

  51. //移除事件,清理资源

  52. Camera.main.RemoveCommandBuffer(CameraEvent.BeforeForwardOpaque, commandBuffer);

  53. commandBuffer.Clear();

  54. renderTexture.Release();

  55. }

  56.  
  57. //为方便调整,放在update里面了

  58. void Update()

  59. {

  60. _Material.SetFloat("_Brightness", brightness);

  61. _Material.SetFloat("_Saturation", saturation);

  62. _Material.SetFloat("_Contrast", contrast);

  63. }

  64. }

好了,我们美颜相机第二版本就完成了,增加了后处理之后的效果,调整了一下饱和度,亮度,对比度之后的效果如下:

动态效果:

 

通过上面的几个例子,我们大概了解了Command Buffer能干的事情。首先,Command Buffer可以让我们定义一连串的渲染指令,我们可以直接在需要的时候通过Graphics.ExecuteCommandBuffer执行也可以通过Camera.AddCommandBuffer函数根据不同的CameraEvent来控制CommandBuffer执行的时间。其次,Command Buffer的效果大致等同于新建一个和主相机参数大致相同的摄像机,并且可以附加一些额外的渲染效果支持,比如替换材质渲染,对渲染的RT进行后处理等等。

 

不过这里我也遇到了一个问题,当使用Command Buffer渲染时,对象的shader使用diffuse等自定义shader的话,Command Buffer渲染出来的结果有时会不对,通过Frame Debuger看的时候发现Command Buffer渲染的流程是Deffer Path的,而不是我们正常的Forward Path,而工程设置以及相机设置都为Forward Path。将shader换为自己写的就木有这个问题。不知道是我哪里姿势不对还是Unity的bug。。。

 

“假”景深效果

 

所谓假景深,叫做背景虚化更加贴切一些。其实所有的渲染效果都是假的,都是是忽悠我们的眼睛,就比谁忽悠得又好又省。正常的景深效果,一般是基于深度计算,根据焦距将模糊图与原图插值控制焦点距离清晰,原理焦点距离模糊。but,这个效果虽然很好,但是需要深度信息,如果是deffer或者开了实时阴影,深度自然就有了,也就无所谓了,但是一般手游的基本这两种都是开不得的,那么开了深度,就会DC翻倍,再加上模糊至少十次全屏采样(降采样也许会好些)。个人感觉景深应该最昂贵的后处理效果之一了。而背景虚化的效果,简单来说就是只让人物(或者我们需要突出的部分)清晰,其他所有部分全都模糊。这种效果不需要深度图,可以在DC上省下很多消耗,而且有时候这种效果会比真正的景深更好,但还是需要看需求。我们如果实现这种效果,最简单的并且容易想到的就是新建一个相机,然后将需要突出的部分放在另一个相机渲染,在场景相机上增加一个模糊的后处理,这样,突出部分渲染后的相机叠加到场景相机的结果上,就可以只让场景模糊而人物不模糊了。不过在有了Command Buffer之后,就不需要这么麻烦了,我们可以直接通过Command Buffer控制模型的渲染时机,首先将正常的Renderer组件disable,然后强行通过Command Buffer让其在后处理之后渲染:

 
  1. //在后处理之后渲染

  2. //by: puppet_master

  3. //2017.6.5

  4.  
  5. using System.Collections;

  6. using System.Collections.Generic;

  7. using UnityEngine;

  8. using UnityEngine.Rendering;

  9. [ExecuteInEditMode]

  10.  
  11. public class RenderAfterPostEffect : MonoBehaviour

  12. {

  13. private CommandBuffer commandBuffer = null;

  14. private Renderer targetRenderer = null;

  15.  
  16. void OnEnable()

  17. {

  18. targetRenderer = this.GetComponentInChildren<Renderer>();

  19. if (targetRenderer)

  20. {

  21. commandBuffer = new CommandBuffer();

  22. commandBuffer.DrawRenderer(targetRenderer, targetRenderer.sharedMaterial);

  23. //直接加入相机的CommandBuffer事件队列中,

  24. Camera.main.AddCommandBuffer(CameraEvent.AfterImageEffects, commandBuffer);

  25. targetRenderer.enabled = false;

  26. }

  27. }

  28.  
  29. void OnDisable()

  30. {

  31. if (targetRenderer)

  32. {

  33. //移除事件,清理资源

  34. Camera.main.RemoveCommandBuffer(CameraEvent.AfterImageEffects, commandBuffer);

  35. commandBuffer.Clear();

  36. targetRenderer.enabled = true;

  37. }

  38. }

  39. }

上面的脚本只是控制修改模型渲染时机的,然后,我们可以在主相机上挂一个高斯模糊的后处理,调整参数后就可以得到背景虚化的效果了:

当然,不仅仅是模糊效果,挂了该脚本的对象会被所有后处理所“抛弃”,我们也可以放一些其他的后处理效果,比如漩涡扭曲:

Command Buffer的这个功能是个人感觉最有用的一个功能,可以进一步地控制某个对象的渲染序列,让我们更加方便地实现一些效果。

 

描边效果Command Buffer实现

 

描边效果(后处理版本)首先将要描边的对象用描边色渲染到一张RT上,然后将RT进行模糊操作,使对象外扩,再用外扩的RT减去原始RT就得到了轮廓部分,最后再将轮廓部分与原图混合就得到了最终的描边效果。描边效果将对象渲染到RT上之前通过额外创建一个摄像机实现的,有了Command Buffer,我们就可以直接在原始相机上进行这个操作,大大简化了程序的复杂度。关于描边效果的具体原理,可以参考本人之前的文章,这里就不多说了,直接上代码。补充说明:PostEffectBase类是所有本人之前做的后处理效果的基类。

C#脚本部分:

 
  1. /********************************************************************

  2. FileName: OutlinePostEffectCmdBuffer.cs

  3. Description: 后处理描边效果CommandBuffer版本

  4. Created: 2017/06/07

  5. by puppet_master

  6. *********************************************************************/

  7. using UnityEngine;

  8. using System.Collections;

  9. using UnityEngine.Rendering;

  10.  
  11. public class OutlinePostEffectCmdBuffer : PostEffectBase

  12. {

  13. private RenderTexture renderTexture = null;

  14. private CommandBuffer commandBuffer = null;

  15. private Material outlineMaterial = null;

  16. //描边prepass shader(渲染纯色贴图的shader)

  17. public Shader outlineShader = null;

  18. //采样率

  19. public float samplerScale = 1;

  20. //降采样

  21. public int downSample = 1;

  22. //迭代次数

  23. public int iteration = 2;

  24. //描边颜色

  25. public Color outLineColor = Color.green;

  26. //描边强度

  27. [Range(0.0f, 10.0f)]

  28. public float outLineStrength = 3.0f;

  29. //目标对象

  30. public GameObject targetObject = null;

  31.  
  32.  
  33. void OnEnable()

  34. {

  35. if (outlineShader == null)

  36. return;

  37. if (outlineMaterial == null)

  38. outlineMaterial = new Material(outlineShader);

  39. Renderer[] renderers = targetObject.GetComponentsInChildren<Renderer>();

  40. if (renderTexture == null)

  41. renderTexture = RenderTexture.GetTemporary(Screen.width >> downSample, Screen.height >> downSample, 0);

  42. //创建描边prepass的command buffer

  43. commandBuffer = new CommandBuffer();

  44. commandBuffer.SetRenderTarget(renderTexture);

  45. commandBuffer.ClearRenderTarget(true, true, Color.black);

  46. foreach (Renderer r in renderers)

  47. commandBuffer.DrawRenderer(r, outlineMaterial);

  48. }

  49.  
  50. void OnDisable()

  51. {

  52. if (renderTexture)

  53. {

  54. RenderTexture.ReleaseTemporary(renderTexture);

  55. renderTexture = null;

  56. }

  57. if (outlineMaterial)

  58. {

  59. DestroyImmediate(outlineMaterial);

  60. outlineMaterial = null;

  61. }

  62. if (commandBuffer != null)

  63. {

  64. commandBuffer.Release();

  65. commandBuffer = null;

  66. }

  67.  
  68. }

  69.  
  70. void OnRenderImage(RenderTexture source, RenderTexture destination)

  71. {

  72. if (_Material && renderTexture && outlineMaterial && commandBuffer != null)

  73. {

  74. //通过Command Buffer可以设置自定义材质的颜色

  75. outlineMaterial.SetColor("_OutlineCol", outLineColor);

  76. //直接通过Graphic执行Command Buffer

  77. Graphics.ExecuteCommandBuffer(commandBuffer);

  78.  
  79. //对RT进行Blur处理

  80. RenderTexture temp1 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0);

  81. RenderTexture temp2 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0);

  82.  
  83. //高斯模糊,两次模糊,横向纵向,使用pass0进行高斯模糊

  84. _Material.SetVector("_offsets", new Vector4(0, samplerScale, 0, 0));

  85. Graphics.Blit(renderTexture, temp1, _Material, 0);

  86. _Material.SetVector("_offsets", new Vector4(samplerScale, 0, 0, 0));

  87. Graphics.Blit(temp1, temp2, _Material, 0);

  88.  
  89. //如果有叠加再进行迭代模糊处理

  90. for(int i = 0; i < iteration; i++)

  91. {

  92. _Material.SetVector("_offsets", new Vector4(0, samplerScale, 0, 0));

  93. Graphics.Blit(temp2, temp1, _Material, 0);

  94. _Material.SetVector("_offsets", new Vector4(samplerScale, 0, 0, 0));

  95. Graphics.Blit(temp1, temp2, _Material, 0);

  96. }

  97.  
  98. //用模糊图和原始图计算出轮廓图

  99. _Material.SetTexture("_BlurTex", temp2);

  100. Graphics.Blit(renderTexture, temp1, _Material, 1);

  101.  
  102. //轮廓图和场景图叠加

  103. _Material.SetTexture("_BlurTex", temp1);

  104. _Material.SetFloat("_OutlineStrength", outLineStrength);

  105. Graphics.Blit(source, destination, _Material, 2);

  106.  
  107. RenderTexture.ReleaseTemporary(temp1);

  108. RenderTexture.ReleaseTemporary(temp2);

  109. }

  110. else

  111. {

  112. Graphics.Blit(source, destination);

  113. }

  114. }

  115.  
  116.  
  117. }

描边后处理部分shader:

 
  1. //后处理描边Shader

  2. //by:puppet_master

  3. //2017.6.7

  4.  
  5. Shader "Custom/OutLinePostEffect" {

  6.  
  7. Properties{

  8. _MainTex("Base (RGB)", 2D) = "white" {}

  9. _BlurTex("Blur", 2D) = "white"{}

  10. }

  11.  
  12. CGINCLUDE

  13. #include "UnityCG.cginc"

  14.  
  15. //用于剔除中心留下轮廓

  16. struct v2f_cull

  17. {

  18. float4 pos : SV_POSITION;

  19. float2 uv : TEXCOORD0;

  20. };

  21.  
  22. //用于模糊

  23. struct v2f_blur

  24. {

  25. float4 pos : SV_POSITION;

  26. float2 uv : TEXCOORD0;

  27. float4 uv01 : TEXCOORD1;

  28. float4 uv23 : TEXCOORD2;

  29. float4 uv45 : TEXCOORD3;

  30. };

  31.  
  32. //用于最后叠加

  33. struct v2f_add

  34. {

  35. float4 pos : SV_POSITION;

  36. float2 uv : TEXCOORD0;

  37. float2 uv1 : TEXCOORD1;

  38. };

  39.  
  40. sampler2D _MainTex;

  41. float4 _MainTex_TexelSize;

  42. sampler2D _BlurTex;

  43. float4 _BlurTex_TexelSize;

  44. float4 _offsets;

  45. float _OutlineStrength;

  46.  
  47. //Blur图和原图进行相减获得轮廓

  48. v2f_cull vert_cull(appdata_img v)

  49. {

  50. v2f_cull o;

  51. o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

  52. o.uv = v.texcoord.xy;

  53. //dx中纹理从左上角为初始坐标,需要反向

  54. #if UNITY_UV_STARTS_AT_TOP

  55. if (_MainTex_TexelSize.y < 0)

  56. o.uv.y = 1 - o.uv.y;

  57. #endif

  58. return o;

  59. }

  60.  
  61. fixed4 frag_cull(v2f_cull i) : SV_Target

  62. {

  63. fixed4 colorMain = tex2D(_MainTex, i.uv);

  64. fixed4 colorBlur = tex2D(_BlurTex, i.uv);

  65. //最后的颜色是_BlurTex - _MainTex,周围0-0=0,黑色;边框部分为描边颜色-0=描边颜色;中间部分为描边颜色-描边颜色=0。最终输出只有边框

  66. //return fixed4((colorBlur - colorMain).rgb, 1);

  67. return colorBlur - colorMain;

  68. }

  69.  
  70. //高斯模糊 vert shader(之前的文章有详细注释,此处也可以用BoxBlur,更省一点)

  71. v2f_blur vert_blur(appdata_img v)

  72. {

  73. v2f_blur o;

  74. _offsets *= _MainTex_TexelSize.xyxy;

  75. o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

  76. o.uv = v.texcoord.xy;

  77.  
  78. o.uv01 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1);

  79. o.uv23 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 2.0;

  80. o.uv45 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 3.0;

  81.  
  82. return o;

  83. }

  84.  
  85. //高斯模糊 pixel shader

  86. fixed4 frag_blur(v2f_blur i) : SV_Target

  87. {

  88. fixed4 color = fixed4(0,0,0,0);

  89. color += 0.40 * tex2D(_MainTex, i.uv);

  90. color += 0.15 * tex2D(_MainTex, i.uv01.xy);

  91. color += 0.15 * tex2D(_MainTex, i.uv01.zw);

  92. color += 0.10 * tex2D(_MainTex, i.uv23.xy);

  93. color += 0.10 * tex2D(_MainTex, i.uv23.zw);

  94. color += 0.05 * tex2D(_MainTex, i.uv45.xy);

  95. color += 0.05 * tex2D(_MainTex, i.uv45.zw);

  96. return color;

  97. }

  98.  
  99. //最终叠加 vertex shader

  100. v2f_add vert_add(appdata_img v)

  101. {

  102. v2f_add o;

  103. //mvp矩阵变换

  104. o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

  105. //uv坐标传递

  106. o.uv.xy = v.texcoord.xy;

  107. o.uv1.xy = o.uv.xy;

  108. #if UNITY_UV_STARTS_AT_TOP

  109. if (_MainTex_TexelSize.y < 0)

  110. o.uv.y = 1 - o.uv.y;

  111. #endif

  112. return o;

  113. }

  114.  
  115. fixed4 frag_add(v2f_add i) : SV_Target

  116. {

  117. //取原始场景图片进行采样

  118. fixed4 ori = tex2D(_MainTex, i.uv1);

  119. //取得到的轮廓图片进行采样

  120. fixed4 blur = tex2D(_BlurTex, i.uv);

  121. fixed4 final = ori + blur * _OutlineStrength;

  122. return final;

  123. }

  124.  
  125. ENDCG

  126.  
  127. SubShader

  128. {

  129. //pass 0: 高斯模糊

  130. Pass

  131. {

  132. ZTest Off

  133. Cull Off

  134. ZWrite Off

  135. Fog{ Mode Off }

  136.  
  137. CGPROGRAM

  138. #pragma vertex vert_blur

  139. #pragma fragment frag_blur

  140. ENDCG

  141. }

  142.  
  143. //pass 1: 剔除中心部分

  144. Pass

  145. {

  146. ZTest Off

  147. Cull Off

  148. ZWrite Off

  149. Fog{ Mode Off }

  150.  
  151. CGPROGRAM

  152. #pragma vertex vert_cull

  153. #pragma fragment frag_cull

  154. ENDCG

  155. }

  156.  
  157.  
  158. //pass 2: 最终叠加

  159. Pass

  160. {

  161.  
  162. ZTest Off

  163. Cull Off

  164. ZWrite Off

  165. Fog{ Mode Off }

  166.  
  167. CGPROGRAM

  168. #pragma vertex vert_add

  169. #pragma fragment frag_add

  170. ENDCG

  171. }

  172.  
  173. }

  174. }

描边PrePass部分shader:

 
  1. //描边Shader

  2. //by:puppet_master

  3. //2017.6.7

  4.  
  5. Shader "ApcShader/OutlinePrePass"

  6. {

  7. //子着色器

  8. SubShader

  9. {

  10. //描边使用两个Pass,第一个pass沿法线挤出一点,只输出描边的颜色

  11. Pass

  12. {

  13. CGPROGRAM

  14. #include "UnityCG.cginc"

  15. fixed4 _OutlineCol;

  16.  
  17. struct v2f

  18. {

  19. float4 pos : SV_POSITION;

  20. };

  21.  
  22. v2f vert(appdata_full v)

  23. {

  24. v2f o;

  25. o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

  26. return o;

  27. }

  28.  
  29. fixed4 frag(v2f i) : SV_Target

  30. {

  31. //这个Pass直接输出描边颜色

  32. return _OutlineCol;

  33. }

  34.  
  35. //使用vert函数和frag函数

  36. #pragma vertex vert

  37. #pragma fragment frag

  38. ENDCG

  39. }

  40. }

  41. }

将描边prepass和后处理shader赋给脚本,并将需要描边的对象赋给targetObject,就可以看到描边效果了:

与之前的描边效果一致,但是代码更简洁。并且描边颜色可以直接在脚本中设置。顺便来一发好玩的效果,调整Sampler Scale以及OutLineStrength:



 

 

 

  • lynnlwl

    lynnlwl: 你好大神,我将OutlinePostEffectCmdBufffer脚本放在物体身上,运行的时候,物体没有出现描边,是哪里出问题了呢?(06-27 15:28#9楼)查看回复(1)

  • zjq2008wd

    Ron_Tang: 看了你一系列的文章,受益匪浅,谢谢分享,已赞。之前做背景虚化使用额外摄像机来的,使用Command Buffer确实方便很多。 现在Unity2018 发布SRP了。期待你更多的文章,加油~~~~(04-20 16:57#8楼)查看回复(1)

  • ipud2

    ipud2: 感谢你的细心分享,唯一不太明白的是为什么,进行blur时一定要分horizontal与vertical,而不是一次全部处理, 比如最简单的模糊处理: fixed4 blurColor = fixed4(0,0,0,0); //blurColor += tex2D(_MainTex, i.uv); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(-1,1)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(0,1)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(1,1)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(-1,0)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(0,0)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(1,0)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(-1,-1)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(0,-1)); blurColor += tex2D(_BaseTexture,i.uv+_BaseTexture_TexelSize.xy*float2(1,-1)); blurColor /= 9;(01-10 21:19#7楼)查看回复(3)

  • wzm19941229

    wzm19941229: 想请教一下对于UI(UGUI)要如何抓取呢?这里抓取依靠Renderer,但是CanvasRenderer和Renderer不同源。。很苦恼。不知道有没有研究过抓取UI?(08-28 16:57#6楼)查看回复(1)

相关文章:

  • Cookies
  • Ogre 材质参数
  • 转:辐射度算法(radiosity)原理
  • GGX
  • Predefined Shader preprocessor macros //预定义的着色器预处理宏
  • (145)光线追踪距离场柔和阴影
  • MaterialTemplate.ush
  • Monoscopic Far Field Rendering
  • Ray Tracing From Ground Up
  • 图形学数学基础之Hammersley采样
  • 图形学基础(5)——Sobol 采样
  • Hammersley–Clifford theorem
  • Sobol sequence generator
  • PaniniProjection
  • Shadowmask
  • 0x05 Python数据分析,Anaconda八斩刀
  • Angular Elements 及其运作原理
  • GitUp, 你不可错过的秀外慧中的git工具
  • HTTP那些事
  • JAVA_NIO系列——Channel和Buffer详解
  • k8s 面向应用开发者的基础命令
  • TCP拥塞控制
  • vue-cli3搭建项目
  • 从0实现一个tiny react(三)生命周期
  • 第2章 网络文档
  • 简单数学运算程序(不定期更新)
  • 前端面试总结(at, md)
  • 小程序01:wepy框架整合iview webapp UI
  • No resource identifier found for attribute,RxJava之zip操作符
  • #设计模式#4.6 Flyweight(享元) 对象结构型模式
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • $.ajax()
  • ${factoryList }后面有空格不影响
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (C语言)输入一个序列,判断是否为奇偶交叉数
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (十八)三元表达式和列表解析
  • .NET 发展历程
  • .NET企业级应用架构设计系列之开场白
  • .NET性能优化(文摘)
  • .NET学习教程二——.net基础定义+VS常用设置
  • /ThinkPHP/Library/Think/Storage/Driver/File.class.php  LINE: 48
  • ;号自动换行
  • @PreAuthorize注解
  • [ SNOI 2013 ] Quare
  • [ 渗透测试面试篇 ] 渗透测试面试题大集合(详解)(十)RCE (远程代码/命令执行漏洞)相关面试题
  • [ 云计算 | AWS 实践 ] 基于 Amazon S3 协议搭建个人云存储服务
  • [2008][note]腔内级联拉曼发射的,二极管泵浦多频调Q laser——
  • [2016.7 test.5] T1
  • [Angular 基础] - 表单:响应式表单
  • [DAX] MAX函数 | MAXX函数
  • [hdu 3746] Cyclic Nacklace [kmp]
  • [HeadFrist-HTMLCSS学习笔记][第一章Web语言:开始了解HTML]
  • [idea]关于idea开发乱码的配置