时间:2023-05-20 06:28:01 | 来源:网站运营
时间:2023-05-20 06:28:01 来源:网站运营
[Unity 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 是为了即时将变化在屏幕上显示出来。//噪波算法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;
一般情况下移动方向是新位置减去之前的位置,但是这样会导致残影优先移动了过去,什么意思呢?就是下面这个情况关键词:效果