shader力场ForceFiled冲击波效果

力场效果(本来就渣,录屏效果是更渣~~)

冲击波

类似水波纹
从无到有的溶解

(1)这里冲击波,主要是利用粒子particle系统,每次点击交互 发射一个粒子,
(2)每个粒子在自己的生命周期中大小都是可以控制的: 由小变大 或者 由大变小 , 总之就是曲线可控。
(3)每个冲击波的大小 和 每个粒子的大小 同步, 粒子决定冲击波

效果中用到知识点 在前面的章节中已经详细介绍了
水波纹
三平面映射
溶解
流光原理

下面直接贴上代码:

Shader "Unlit/ForceFiled_first_HitWave"
{
    
    
	Properties
	{
    
    
		_NoiseTex ("_NoiseTex", 2D) = "white" {
    
    }
		_RampTex ("_RampTex", 2D) = "white" {
    
    }
		// _HitPos("HitPos",vector) = (0,0,0,0)
		// _HitSize("_HitSize",float) = 1
		_HitSpread("_HitSpread",float) = 1
		_NoiseIntensity("_NoiseIntensity",float) = 1
		

		_HitFadeDistance("扩散的距离限制,最后到末尾时会消隐_HitFadeDistance",float) = 5
		_HitFadePower("_HitFadePower",float) = 1

		_AffectorAmount("_AffectorAmount",float) = 20

		///  溶解值的计算:

		_DissolveRampTex("_DissolveRampTex",2D) = "white"{
    
    }

		_DissolvePoint("溶解开始点_DissolvePoint",vector) = (0,0,0,0)
		_DissolveNoisePower("_DissolveNoisePower",float) = 1
		_DissolveAmount("_DissolveAmoun溶解程度",float) = 0.5
		_DissolveSpread("_DissolveSpread",float) = 1
		_DissolveEdgeIntensity("_DissolveEdgeIntensity",float) = 1


		//  RimColod
		_FresnalPower("Fresnal Power",float) = 3
		_FresnalScale("_FresnalScale",float) = 0.8
		_FresnalBias("_FresnalBias",float) = 0.16



		//  _FlowMap
		_FlowLightTex("_FlowLightTex",2D) = "white"{
    
    }
		_FlowMap("_FlowMap",2D) = "white"{
    
    }
		_FlowSpeed("_FlowSpeed",float) = 0.2
		_FlowStrength("_FlowStrength",vector) = (0.2,0.2,0,0)

		// 三平面映射相关
		_Contrast("_Contrast法线遮罩的对比度",float) = 1
		_TriPlanarTilling("_TriPlanarTilling 三平面映射的缩放平移",vector) = (1,1,0,0)


		// 冲击波强度
		_HitWaveIntensity("_HitWaveIntensity",float) = 1.3


		//自发光
		_EmissColor("_EmissColor",color) = (1,1,1,1)
		_EmissIntensity("_EmissIntensity",float) = 2


	}
	SubShader
	{
    
    

		//  半透明  三件套 : Queue修改     Blend   Zwrite  
		//  计算完的 向量   在 使用前  归一化!!!!
		Tags {
    
     "RenderType"="Transparent"  "Queue" = "Transparent"}
		Cull back
		Zwrite off
		Blend SrcAlpha OneMinusSrcAlpha
		LOD 100

		Pass
		{
    
    
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			// make fog work
			#pragma multi_compile_fog
			
			#include "UnityCG.cginc"

			struct appdata
			{
    
    
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
				float3 normal : NORMAL;

			};

			struct v2f
			{
    
    
				float2 uv : TEXCOORD0;
				float4 vertex : SV_POSITION;
				float3 worldPos : TEXCOORD1;
				float3 PivotPos : TEXCOORD2;
				float2 uv_FlowMap : TEXCOORD3;
				float3 worldNormal : TEXCOORD4;
			};

			sampler2D _NoiseTex,_RampTex;
			float4 _NoiseTex_ST;
		
			float _HitFadeDistance,_HitFadePower,_HitSpread,_NoiseIntensity;
			
			float _AffectorAmount;
			uniform float HitSize[20];
			uniform float4 HitPosition[20];

			/  溶解相关参数:
			sampler2D _DissolveRampTex;
			float3 _DissolvePoint;
			float _DissolveNoisePower, _DissolveAmount, _DissolveSpread,  _DissolveEdgeIntensity;

			///  菲涅尔相关
			float _FresnalPower, _FresnalScale,_FresnalBias;




			sampler2D _FlowMap,_FlowLightTex;
			float4 _FlowMap_ST;
			float4 _FlowStrength;
			float _FlowSpeed;
			

			float _HitWaveIntensity,_EmissIntensity;
			float4 _EmissColor;

			// 三平面映射相关参数
			float4 _TriPlanarTilling;
			float _Contrast;
			// 根据法线的三个轴  生成遮罩
			float3 NorMalMask(float3 wNormal)
			{
    
    
				float3 tempNormal =  pow(abs(wNormal),_Contrast);
				float3 mask = tempNormal /(tempNormal.x + tempNormal.y + tempNormal.z);
				return mask;
			}

			   三平面映射
			float4 TriPlanar(float3 maskValue,float3 worldPos,float3 worldPivot,sampler2D mainTex)
			{
    
    
				float3 tempPos = ((worldPos - worldPivot) * _TriPlanarTilling.xyz).xyz;
				//  xy 平面的像素正常显示 但是  其他轴对应平面的值不正确,所以 乘以 maskValue.z,屏蔽掉其它轴面的值。
				float4 colorZ = tex2D(mainTex,tempPos.xy) * maskValue.z;
				float4 colorY = tex2D(mainTex,tempPos.xz) * maskValue.y;
				float4 colorX = tex2D(mainTex,tempPos.yz) * maskValue.x;
				//  三个轴面的正确结果相加  ,  归一化
				return normalize(colorX + colorY + colorZ); 
			}


			/// 计算冲击波
			float HitWave(float3 worldPos,float waveNoise)
			{
    
    
				float hitResult=0;				
				for(int j=0;j<_AffectorAmount; j++)
				{
    
    
					float distanceMask = distance(HitPosition[j].xyz,worldPos);
					float hitRange = -clamp( (distanceMask - HitSize[j] + waveNoise) / _HitSpread,-1.0,0.0);
					float2 mapUV = float2(hitRange,0.5);
					float2 hitWave = tex2D(_RampTex,mapUV).r;
					float hitFade = saturate((1.0 - distanceMask / _HitFadeDistance) * _HitFadePower);
					hitResult = hitResult + hitFade * hitWave;
				}
				return hitResult;
			}

			// 返回值是两个: x alphaMask遮罩;  y edge溶解边缘的两边
			float2 DissolveFactor(float3 worldPos,float3 PivotPos,float noiseData)
			{
    
    
				
			 	float dissolveX = 1 - clamp(((_DissolvePoint - (worldPos - PivotPos)) - noiseData ) / _DissolveSpread,0.0,1.0);
			
				float dissolveAlpha = smoothstep(0.0,0.1,dissolveX);

				float dissolveEdge = tex2D(_DissolveRampTex,float2(dissolveX,0.5)).r * _DissolveEdgeIntensity;

				return float2(dissolveAlpha, dissolveEdge); 
			
			}


			// 流光贴图采样计算结果
			float4 flowMap(float flowSpeed,float2 flowIntensity,sampler2D mainTex,sampler2D flowMap,float2 maintexUV,float2 flowmapUV)
			{
    
    
				//
				float2 timeDetla = frac(_Time.y * flowSpeed) * flowIntensity;
				//
				float2 timeNext = frac(_Time.y * flowSpeed + 0.5) * flowIntensity;

				// 两个时间的插值因子
				float timeLerp  = abs(frac(_Time.y * flowSpeed)* 2 -1);
				
				// 此处flowMap中存的值范围 (0,1),   但是向量的方向是(-1,1), 可以转化*2-1  ;  0.5- tex2D() 将值范围限制在(-0.5,0.5)之间,这样看起来效果比较舒服!!!
				float2 flowDir = (0.5 - tex2D(flowMap,flowmapUV).rg);
				float2 uvOffset1 = flowDir * timeDetla;
				float4 mainDetlaCol = tex2D(mainTex,maintexUV + uvOffset1);
				float2 uvOffset2 = flowDir * timeNext;
				float4 mainNextCol = tex2D(mainTex,maintexUV + uvOffset2);
				float4 endCol = lerp(mainDetlaCol,mainNextCol,timeLerp);
			
				return endCol;
			}

			v2f vert (appdata v)
			{
    
    
				v2f o;
				o.vertex = UnityObjectToClipPos(v.vertex);
				o.uv = TRANSFORM_TEX(v.uv, _NoiseTex);
				o.uv_FlowMap = TRANSFORM_TEX(v.uv, _FlowMap);
				o.worldPos = mul(unity_ObjectToWorld,v.vertex);
				o.PivotPos = mul(unity_ObjectToWorld,float4(0,0,0,1));
				o.worldNormal = UnityObjectToWorldDir(v.normal);
				return o;
			}


			fixed4 frag (v2f i) : SV_Target
			{
    
    
				float3 worldNormal = normalize(i.worldNormal);

				/// -------三平面映射
				float3 normalMask = NorMalMask(worldNormal);
				float waveNoise = TriPlanar(normalMask, i.worldPos, i.PivotPos,_NoiseTex);

				-------冲击波---------
				float hitWave = HitWave(i.worldPos,waveNoise);

				
				  --------- 溶解参数-------
				float tempData =   1 -clamp( ( ( distance(_DissolvePoint.xyz , i.worldPos.xyz -  i.PivotPos.xyz) - _DissolveAmount - (waveNoise * _DissolveNoisePower)) / _DissolveSpread ),0.0,1.0);
				float dissolveAlphaMask = smoothstep(tempData,0.0,0.1);
				float dissolveEdge = tex2D(_DissolveRampTex,float2(tempData,0.5)).r * _DissolveEdgeIntensity;
			
	
				/// ------- 菲涅尔 边缘光-------
				float3 worldView = normalize(UnityWorldSpaceViewDir(i.worldPos));
				float fresnal = _FresnalBias +  _FresnalScale * pow(1 - (dot( worldNormal,worldView)),_FresnalPower); 
				float4 emissionCol = _EmissColor * _EmissIntensity;
			
			
				///----------------流光-----
				float2 flowMapUV = float2(i.uv_FlowMap + hitWave);
				float4 flowColor = flowMap(_FlowSpeed,_FlowStrength.xy,_FlowLightTex,_FlowMap,i.uv,flowMapUV);
        		
		
				///  ---------最后的颜色结果计算 ---------
				float4 mainCol = fresnal * flowColor;
				//  柔性叠加  加上0.5是为了提亮一点底色,不然冲击波太淡了
				mainCol =  (mainCol + 0.5) * ( hitWave * _HitWaveIntensity ) + mainCol + dissolveEdge;
				float endAlpha  = clamp(Luminance(mainCol.a) * dissolveAlphaMask ,0,1) ;
				float3 endCol = mainCol * emissionCol;

				return float4(endCol,endAlpha);
			}
			ENDCG
		}
	}
}

C#脚本 点击交互:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.UIElements;

[ExecuteInEditMode]
public class ForceFiled : MonoBehaviour
{
    
    
	public ParticleSystem ps;
	public string triggerTag = "ForceFiled";

	public float clickPerSecond = 0.1f;
	private float clickTimer = 0;

	public int AffectorAmount = 20;
	private ParticleSystem.Particle[] particles;
	private Vector4[] positions;
	private float[] sizes;
	private Material mat;
	
	private void Start()
	{
    
    
		mat = GetComponent<MeshRenderer>().sharedMaterial;
	}

	void DoRayCast()
	{
    
    
		Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
		RaycastHit hitInfo;
		if (Physics.Raycast(ray,out  hitInfo,1000))
		{
    
    
			if (hitInfo.transform.CompareTag(triggerTag))
			{
    
    
				ps.transform.position = hitInfo.point;
				ps.Emit(1);
			}
		}
	}

	
	void Update () {
    
    

		
		if (Input.GetMouseButton(0))
		{
    
    
			clickTimer += Time.deltaTime;
			if (clickTimer >= clickPerSecond)
			{
    
    
				clickTimer = 0;
				DoRayCast();
			}
		}

		particles = new ParticleSystem.Particle[AffectorAmount];
		positions = new Vector4[AffectorAmount];
		sizes = new float[AffectorAmount];
		ps.GetParticles(particles);

		for (int i = 0; i < AffectorAmount; i++)
		{
    
    
			positions[i] = particles[i].position;
			sizes[i] = particles[i].GetCurrentSize(ps);
		}
		mat.SetVectorArray("HitPosition", positions);
		mat.SetFloatArray("HitSize", sizes);
		mat.SetFloat("AffectorAmount", AffectorAmount);
		
		// Shader.SetGlobalVectorArray("HitPosition", positions);
		// Shader.SetGlobalFloatArray("HitSize", sizes);
		// Shader.SetGlobalFloat("AffectorAmount", AffectorAmount);
	}
}

下载链接:力场

猜你喜欢

转载自blog.csdn.net/js0907/article/details/119061158
今日推荐