前阵子组长给我提了个需求,要实现角色人物的残影。我百度google了一下,发现可以用两种方式实现这个效果:1.记录前几帧的人物位置,将其传入shader中,对每个位置进行一个pass渲染。2. 通过相机的targetRender,记录前几帧的人物的影像,然后通过后处理混合上去。

这里先介绍方法1,先看效果:

残影用了alpha混合的方法,将它们变得透明。

先列出shader代码:

  1. Shader "Custom/Ghost" {
  2. Properties {
  3. _MainTex ("Main Tex", 2D) = "white" {}
  4. _Offset0 ("Offset 0", vector) = (, , , ) // 这里只显示4个残影,所以传入4个偏移值
  5. _Offset1 ("Offset 1", vector) = (, , , )
  6. _Offset2 ("Offset 2", vector) = (, , , )
  7. _Offset3 ("Offset 3", vector) = (, , , )
  8. }
  9.  
  10. CGINCLUDE
  11. #include "UnityCG.cginc"
  12.  
  13. sampler2D _MainTex;
  14.  
  15. float4 _Offset0;
  16. float4 _Offset1;
  17. float4 _Offset2;
  18. float4 _Offset3;
  19.  
  20. struct v2f {
  21. float4 pos : POSITION;
  22. float2 uv : TEXCOORD0;
  23. };

  24.     // 在shader中要渲染自身,以及4个残影,所以要定义5个不同的vert函数
  25. v2f vert_normal(appdata_base v) { // 渲染自身的vert函数
  26. v2f o;
  27. o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
  28. o.uv = v.texcoord;
  29. return o;
  30. }
  31.     // 渲染4个残影的vert函数
  32. v2f vert_offset_1(appdata_base v) {
  33. v2f o;
  34. float4 pos = mul(_Object2World, v.vertex);
  35. o.pos = mul(UNITY_MATRIX_VP, pos + _Offset0);
  36. o.uv = v.texcoord;
  37. return o;
  38. }
  39.  
  40. v2f vert_offset_2(appdata_base v) {
  41. v2f o;
  42. float4 pos = mul(_Object2World, v.vertex);
  43. o.pos = mul(UNITY_MATRIX_VP, pos + _Offset1);
  44. o.uv = v.texcoord;
  45. return o;
  46. }
  47.  
  48. v2f vert_offset_3(appdata_base v) {
  49. v2f o;
  50. float4 pos = mul(_Object2World, v.vertex);
  51. o.pos = mul(UNITY_MATRIX_VP, pos + _Offset2);
  52. o.uv = v.texcoord;
  53. return o;
  54. }
  55.  
  56. v2f vert_offset_4(appdata_base v) {
  57. v2f o;
  58. float4 pos = mul(_Object2World, v.vertex);
  59. o.pos = mul(UNITY_MATRIX_VP, pos + _Offset3);
  60. o.uv = v.texcoord;
  61. return o;
  62. }
  63.     
         
        // 这里只定义了两个frag函数,分别是渲染自身,以及残影的
  64. float4 frag_normal(v2f i) : COLOR {
  65. return tex2D(_MainTex, i.uv);
  66. }
  67.  
  68. float4 frag_color(v2f i) : COLOR { // 将残影的alpha值设为0.5
  69. float4 c;
  70. c = tex2D(_MainTex, i.uv);
  71. c.w = 0.5;
  72. return c;
  73. }
  74. ENDCG
  75.  
  76. SubShader { // 这里用4个pass来渲染残影,第5个pass渲染自身
  77. Pass { // 从最远的开始渲染
  78. ZWrite Off
  79. Blend SrcAlpha OneMinusSrcAlpha
  80.  
  81. CGPROGRAM
  82. #pragma vertex vert_offset_4
  83. #pragma fragment frag_color
  84. ENDCG
  85. }
  86.  
  87. Pass {
  88. ZWrite Off
  89. Blend SrcAlpha OneMinusSrcAlpha
  90.  
  91. CGPROGRAM
  92. #pragma vertex vert_offset_3
  93. #pragma fragment frag_color
  94. ENDCG
  95. }
  96.  
  97. Pass {
  98. ZWrite Off
  99. Blend SrcAlpha OneMinusSrcAlpha
  100.  
  101. CGPROGRAM
  102. #pragma vertex vert_offset_2
  103. #pragma fragment frag_color
  104. ENDCG
  105. }
  106.  
  107. Pass {
  108. ZWrite Off
  109. Blend SrcAlpha OneMinusSrcAlpha
  110.  
  111. CGPROGRAM
  112. #pragma vertex vert_offset_1
  113. #pragma fragment frag_color
  114. ENDCG
  115. }
  116.  
  117. Pass { // 渲染自身,这时要开启 ZWrite
  118. Blend SrcAlpha OneMinusSrcAlpha
  119.  
  120. CGPROGRAM
  121. #pragma vertex vert_normal
  122. #pragma fragment frag_normal
  123. ENDCG
  124. }
  125. }
  126. FallBack "Diffuse"
  127. }

看上去挺简单的。这里要注意的一点是,从c#脚本获取的offset值,是在世界坐标中获取的,所以在计算偏移时,要先将坐标转到世界坐标。

  1. float4 pos = mul(_Object2World, v.vertex);
  2. o.pos = mul(UNITY_MATRIX_VP, pos + _Offset0);

接着显示C#脚本:

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. [ExecuteInEditMode]
  6. public class Ghost : MonoBehaviour {
  7. public Shader curShader;
  8. private List<Vector3> offsets = new List<Vector3>(); // 存储前几帧的坐标
  9. private List<Material> mats = new List<Material>(); // 存储人物的材质,用于给shader传参数
  10. // Use this for initialization
  11. void Start ()
  12. {
  13. offsets.Add(transform.position);
  14. offsets.Add(transform.position);
  15. offsets.Add(transform.position);
  16. offsets.Add(transform.position);
  17.  
  18. var skinMeshRenderer = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
  19. foreach (var mr in skinMeshRenderer)
  20. mats.Add(mr.material);
  21.  
  22. var meshRenderer = gameObject.GetComponentsInChildren<MeshRenderer>();
  23. foreach (var mr in meshRenderer)
  24. mats.Add(mr.material);
  25.  
  26. foreach (var mat in mats)
  27. mat.shader = curShader;
  28. }
  29.  
  30. // Update is called once per frame
  31. void Update () {
  32. foreach (var mat in mats) // 每帧将之前的位置传入shader中
  33. {
  34. mat.SetVector("_Offset0", offsets[] - transform.position);
  35. mat.SetVector("_Offset1", offsets[] - transform.position);
  36. mat.SetVector("_Offset2", offsets[] - transform.position);
  37. mat.SetVector("_Offset3", offsets[] - transform.position);
  38. }
  39.  
  40. offsets.Add(transform.position);
  41. offsets.RemoveAt();
  42. }
  43. }

就这样,将C#脚本拖到GameObject身上就可以了

总结:

这个方法相对简单,问题就是,残影是和自身动作是一样的。如果要做成残影保留之前的动作,就需要记录动作参数,或者是直接保存前几帧的RenderTexture。

Unity Shader : Ghost(残影) v1的更多相关文章

  1. unity制作人物残影-绘制的方法

    这里是利用skinnedMeshRenderer原理做的 所以脚本需要挂在带这个组件的模型上 模型shader 必须要有个_Color参数属性,并且这个值可以调节颜色,会改变人物整体的透明度 [代码下 ...

  2. Unity运动残影技能

    残影实现: 1.List<DrawMesh> list,此list中包含某一帧动画模型网格.材质 2.每过一段时间就将运动物体的模型add到list中(优化:未实现,网格合并) 3.Lat ...

  3. cocos2dx - shader实现任意动画的残影效果

    本节主要讲利用cocos2dx机制实现opengl es shader脚本的绘制 这里先看下最终效果:                      这里分别实现了灰度效果及残影的效果. 一.绘制基类 这 ...

  4. Unity角色残影特效

    残影特效在网上有很多例子,比如这个,我参考着自己整合了一下,算是整合了一个比较完整且特别简单易用的出来,只需要一个脚本挂上去无需任何设定就能用. 这里只针对SkinnedMeshRenderer的网格 ...

  5. 【Unity Shader】从NDC(归一化的设备坐标)坐标转换到世界坐标的数学原理

    从NDC(归一化的设备坐标)坐标转换到世界坐标要点 参考资料 How to go from device coordinates back to worldspace http://feepingcr ...

  6. Unity3D手游开发日记(8) - 运动残影效果

    2D游戏的残影很简单,美术做序列帧图片就行了,那么3D游戏的残影美术做不了,得靠程序员动态创建模型来处理. 实现原理也很简单: 1.间隔一定时间创建一个残影模型 GameObject go = Gam ...

  7. Unity3D-Shader-人物残影效果

    [旧博客转移 - 2016年1月7日 00:24 ] 前面的话 上一篇讲了一下人物边缘发光效果,链接: Unity-ShaderLab-实现X光效果,这次我们利用这个Shader来实现人物残影效果 先 ...

  8. Unity Shader - 消融效果原理与变体

    基本原理与实现 主要使用噪声和透明度测试,从噪声图中读取某个通道的值,然后使用该值进行透明度测试. 主要代码如下: fixed cutout = tex2D(_NoiseTex, i.uvNoiseT ...

  9. Unity Shader 玻璃效果

    一个玻璃效果主要分为两个部分,一部分是折射效果的计算,另一部分则是反射.下面分类进行讨论: 折射: 1.利用Grass Pass对当前屏幕的渲染图像进行采样 2.得到法线贴图对折射的影响 3.对采集的 ...

随机推荐

  1. http://www.dayandeng.com/ 诈骗网站

    http://www.dayandeng.com/ 诈骗网站   http://www.dayandeng.com/userfiles/media/2018/awzosv16.html   骗取你的京 ...

  2. Learning Puppet — Variables, Conditionals, and Facts

    Begin $my_variable = "A bunch of text" notify {$my_variable:} Yup, that’s a variable, all ...

  3. NOR Flash擦写和原理分析 (一)

    1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程序可以直接在FLASH片内执行(这意味着存 ...

  4. c++常用的一些库函数、常量和头文件

    1.常用数学函数 头文件 #include <math> 或者 #include <math.h>   函数原型 功能 返回值 int abs(int x) 求整数x的绝对值 ...

  5. 使用 Override 和 New 关键字进行版本控制

    使用 Override 和 New 关键字进行版本控制 C# 语言经过专门设计,以便不同库中的基类与派生类之间的版本控制可以不断向前发展,同时保持向后兼容. 这具有多方面的意义.例如,这意味着在基类中 ...

  6. 单选按钮选中js的处理

    function FinancialinfosetController($scope, $http, $timeout, $location, $rootScope, $routeParams) { ...

  7. Shuffle相关分析

    Shuffle描述是一个过程,表现出的是多对多的依赖关系.Shuffle是连接map阶段和Reduce阶段的纽带,每个Reduce Task都会从Map Task产生的数据里读取其中的一片数据.Shu ...

  8. KMP算法的Next数组详解 转

    这个写的很好,还有讲kmp,值得一看. http://www.cnblogs.com/tangzhengyue/p/4315393.html 转载请注明来源,并包含相关链接. 网上有很多讲解KMP算法 ...

  9. 在tortoiseSVN上将trunk的代码merge到branch上去

    1.进入branch项目的目录 2.右键选择merge 3.下一步 4.选择trunk

  10. Python深入01 特殊方法与多范式

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明. Python一切皆对象,但同时,Python还是一个多范式语言(multi-paradi ...