[Unity Shader]凌波微步效果

相信很多人都看过天龙八部,里面的段誉有一个技能就是凌波微步:移动的时候人先到,衣角跟随其后。说白了就是移动时有一个残影跟着他。下面先看下最终效果

下面我们看如何实现上面的效果。

思路:

1.既然需要移动,那么就需要一个3维(x,y,z三个方向)的数据存储,同时还需要一个变量用来表示偏移强度。

2.需要一个2d贴图来做采样

因此Shader代码很快就出来了

Shader "QShader/UnlitShader_04_1"
{Properties{_MainTex ("MainTex", 2d) = "white"{}_Direction ("Direction", vector) = (0,0,0,1)}SubShader{     Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"sampler2D _MainTex;half4 _Direction;float4 _MainTex_ST;struct appdata{float4 position : POSITION;float2 uv : TEXCOORD0;};struct v2f{float4 position : SV_POSITION;float2 uv:TEXCOORD0;};v2f vert (appdata v){v2f o;v.position.xyz += _Direction.xyz * _Direction.w;o.position = UnityObjectToClipPos(v.position);o.uv = TRANSFORM_TEX(v.uv,_MainTex);return o;}fixed4 frag (v2f i) : SV_Target{ fixed4 col = tex2D(_MainTex,i.uv);return col;}ENDCG}}
}

注意里面的 TRANSFORM_TEX 是为了即时将变化在屏幕上显示出来。

我们先看下效果

我们创建两个材质球,第一个材质球不做任何处理,然后将第二个材质球的Direction变量的X修改为2,将两个物体做个对比观察。

我们发现物体向右边移动了。接下来我们想要的残影效果还没有,我们使用噪波算法实现随机偏移的效果。

//噪波算法
float noise = frac(sin(dot(v.uv.xy, float2(12.9898, 78.233))) * 43758.5453);

我们看到物体是整体都会被拉伸了,但是我们只需要根据他的移动方向做拉伸就好,也就是他的前进方向做拉伸,背面不做拉伸。怎么做呢?

物体在阳光下会有投影,物体的投影,也就是他的反射光线是可以根据入射光线以及他的法线来算出。这里就可以将他的不做拉伸的背面理解为他的反射光线。

那么我们就将这个反射光线作为参数传入进去

//变换拉伸
fixed NdotD = max(0,dot(_Direction,v.normal));
         v2f vert (appdata v){v2f o;  //噪波算法float noise = frac(sin(dot(v.uv.xy, float2(12.9898, 78.233))) * 43758.5453);//变换拉伸fixed NdotD = max(0,dot(_Direction,v.normal));v.position.xyz += _Direction.xyz * _Direction.w * noise * NdotD;o.position = UnityObjectToClipPos(v.position);o.uv = TRANSFORM_TEX(v.uv,_MainTex);return o;}

实际就如上所示。至此完整的Shader代码已经出来了。我们增加了一个Color变量用来在贴图上面添加一个好看的颜色,这里仅是为了美观,可以去掉。

Shader "QShader/UnlitShader_04_2"
{Properties{_Color ("Color",Color) = (0,0,0,1)_MainTex ("MainTex", 2d) = "white"{}_Direction ("Direction", vector) = (0,0,0,1)}SubShader{        Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"sampler2D _MainTex;half4 _Direction;float4 _MainTex_ST;float4 _Color;struct appdata{float4 position : POSITION;float2 uv : TEXCOORD0;half3 normal:NORMAL;};struct v2f{float4 position : SV_POSITION;float2 uv:TEXCOORD0;};v2f vert (appdata v){v2f o;    //噪波算法float noise = frac(sin(dot(v.uv.xy, float2(12.9898, 78.233))) * 43758.5453);//变换拉伸fixed NdotD = max(0,dot(_Direction,v.normal));v.position.xyz += _Direction.xyz * _Direction.w * noise * NdotD;o.position = UnityObjectToClipPos(v.position);o.uv = TRANSFORM_TEX(v.uv,_MainTex);return o;}fixed4 frag (v2f i) : SV_Target{ fixed4 col = tex2D(_MainTex,i.uv);col+=_Color;return col;}ENDCG}}
}

这个时候我们需要一个脚本文件来将物体移动的方向作为参数传给Shader的Direction变量,用来动态显示残影。因此新建AfterglowEffect.cs代码如下

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class AfterglowEffect : MonoBehaviour {private Material[] mats;private Vector3 prePosition;private Vector3 curPosition;private float deltaTime;// Use this for initializationvoid Start(){prePosition = curPosition = transform.position;Renderer[] renderers = transform.GetComponentsInChildren<Renderer>();mats = new Material[renderers.Length];for (int i = 0; i < renderers.Length; i++){Renderer renderer = renderers[i];mats[i] = renderer.sharedMaterial;}}// Update is called once per framevoid Update(){curPosition = transform.position;if (curPosition == prePosition){deltaTime = 0;return;}deltaTime += Time.deltaTime;prePosition = Vector3.Lerp(prePosition,curPosition,deltaTime);Vector3 direction = prePosition- curPosition;for (int i = 0; i < mats.Length; i++){mats[i].SetVector("_Direction", new Vector4(direction.x, direction.y, direction.z, mats[i].GetVector("_Direction").w));}}
}

这里有两个需要注意的地方

prePosition = Vector3.Lerp(prePosition,curPosition,deltaTime);

我们根据之前的位置和当前的位置通过Lerp函数做插值,动态传入就让残影移动的比较平滑。还有一个要注意的是我们的移动方向

Vector3 direction = prePosition- curPosition;

一般情况下移动方向是新位置减去之前的位置,但是这样会导致残影优先移动了过去,什么意思呢?就是下面这个情况

我们的移动方向是向右边,但是残影的方向其实应该是向左边,也就是反过来,这样才是对的。

参考:https://connect.unity.com/p/shaderan-li-ding-dian-yun-dong-mo-hu

欢迎关注微信公众号:Unity游戏开发笔记

QQ群:

[Unity Shader]凌波微步效果相关推荐

  1. Unity Shader 动画效果出现残影

    问题 复现<Unity Shader入门精要>的动画效果时,我发现我的动画都出现了残影. 一开始认为是程序写错了,采样出现了问题,但是复查对比其他资料很多遍也没发现错误. 解决方法 后来反 ...

  2. Unity Shader放大镜效果

    小菜最近看到了一篇关于Shader实现的放大镜效果,酷炫的效果让小菜倍生好奇,冲动之下还是搬来练练手,刚好巩固下自己的顶点片元着色器编码. 有没有想学习的冲动!!! 文章的开始先来介绍一款好用的vs编 ...

  3. Unity Shader 新手引导效果

    这两天实现了下新手引导需要的遮罩镂空shader效果,记录一下. 1.圆形镂空shader代码: //计算片元世界坐标和目标中心位置的距离 float dis = distance(IN.worldP ...

  4. unity Shader 扭曲效果

    原理 所谓扭曲就是扰动一个物体的uv坐标,表现出来就是一个扰动效果,如火焰扭曲空气,和水波对水底的影响. 1. 在shader 中我们需要一张当前渲染的纹理 2. 给一个物体渲染并使用当前纹理,用屏幕 ...

  5. Unity Shader - 描边效果

    原文链接:http://blog.csdn.net/puppet_master/article/details/54000951 简介 描边效果是游戏里面非常常用的一种效果,一般是为了凸显游戏中的某个 ...

  6. Unity Shader透明效果

    在实时渲染中要实现透明效果,通常会在渲染模型时控制他的透明通道.当开启透明混合后,当一个物体被渲染到屏幕上时,每个片元除了颜色值和深度值之外,它还有另一个属性--透明度.当透明度为1时表示该像素是完全 ...

  7. Unity Shader 贴花效果(一)

    本文实现的是一个Mesh Decal方法的贴花方案,参考了本篇博文链接: unity的贴花方案.链接的文章是转载的,我并没有找到原文地址.本篇文章主要是学习和自己的理解为主. 先看未贴花之前的效果 这 ...

  8. 【Unity Shader 消融效果_案例分享】

    1.实现逻辑 消融效果主要是利用了Shader中的clip()函数,也就是透明测试功能,在ASE中叫"Opacity Mask". 消融效果是基于一张"Noise&quo ...

  9. 【Unity Shader 描边效果_案例分享】

    1.实现逻辑 描边效果Shader有多种实现方式,可以通过后处理和MatCap实现. 这次主要想展示的是通过两个Pass实现. 当Shader中有多个Pass时,渲染流程会安装顺序依次执行,于是后面的 ...

最新文章

  1. Caffe实战二(手写体识别例程:CPU、GPU、cuDNN速度对比)
  2. mysql提高缓存_合理配置MySQL缓存 提高缓存命中率
  3. IAR切BANK--程序中的使用
  4. 第七篇:Spring Boot整合Thymeleaf_入门试炼02
  5. tortoisegit 代码的回滚方式 --两种
  6. 关于架设流媒体服务器与DRM加密问题
  7. SpringCloud之实现下载Excel模板文件
  8. 网络营销:信任是流量时代的蓝海
  9. 2021年海河英才计划天津落户天津最详细过程
  10. Icarus主题美化
  11. 【Python】计算文件的MD5、SHA1、SHA256值(校验文件完整性)
  12. Fidder基础知识
  13. 在html里如何下雪花,html加动态雪花
  14. Java获取项目当前请求的全部URL,Java获取Referer,Java获取完整链接地址URL
  15. Oracle数据库安装容易出错问题的解决方案
  16. linux与windows文件互传(scp指令)
  17. navicat12连接SQL Server时出错:未发现数据源名称并且未指定默认驱动程序
  18. 软件工程 - 基于UML的面向对象设计报告模板
  19. dreamweaver (dw)cc 2017
  20. Job for network.service failed虚拟机无法重启网络问题详解

热门文章

  1. python中不可变数据类型有_Python中的可变数据类型有____,不可变数据类型有____。_学小易找答案...
  2. Java基础-this关键字
  3. MySQL高级篇知识点——索引优化与查询优化
  4. List集合的迭代神器ListIterator
  5. {练习题}函数(3)
  6. Get一个全新的网盘工具5T的OneDrive(如何领取免费的5T空间的OneDrive和Office)
  7. 如何优雅的对 Docker 容器进行健康检查
  8. 【鱼眼相机模型】鱼眼相机投影模型理解
  9. 一文辨析 Java、JSP、JavaScript
  10. linux date 时间同步,Linux date 时间设置同步命令分享