15158846557 在线咨询 在线咨询
15158846557 在线咨询
所在位置: 首页 > 营销资讯 > 网站运营 > [Unity Shader]凌波微步效果

[Unity Shader]凌波微步效果

时间:2023-05-20 06:28:01 | 来源:网站运营

时间:2023-05-20 06:28:01 来源:网站运营

[Unity Shader]凌波微步效果:

[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 initialization void 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 frame void 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

========================

《游戏AI程序设计实战》作者

微信公众号:Unity游戏开发笔记

http://weixin.qq.com/r/xzs6Im3ERTA6rSlB927V (二维码自动识别)

QQ群:754814245

欢迎支持我的新书《游戏AI程序设计实战》




关键词:效果

74
73
25
news

版权所有© 亿企邦 1997-2025 保留一切法律许可权利。

为了最佳展示效果,本站不支持IE9及以下版本的浏览器,建议您使用谷歌Chrome浏览器。 点击下载Chrome浏览器
关闭