Estuche de sombreado con efecto de congelación

Primera imagen de las viejas reglas.
Por favor agregue una descripción de la imagen

Recientemente, estoy diseñando un juego independiente con un tema de planeta. Una de las características es el efecto especial de que el monstruo se congela gradualmente y se generan carámbanos debajo de él. Aquí, me gustaría compartir con ustedes mi proceso de diseño.



1. Ajuste la superficie del hielo

En primer lugar, este efecto especial debe encajar estrechamente con el modelo original, y el modelo de origen debe expandirse hacia afuera en la dirección normal para evitar entrelazarse con el modelo original. El código específico es el siguiente:

//因为是叠加在原本的材质上使用的,所以需要比原本的稍微大一些,我们使用向法线方向延展的方式
v.vertex += downNormal * stepNormal + _BaseVectorNormalScale*v.normal;

2. El punto de partida de la congelación

Supongamos que lo que quiere hacer es una función similar a una pistola de congelación. Después de disparar, se congelará desde el punto de impacto. Use RaycastHit.textureCoord para obtener el valor UV del punto de impacto y asígnelo al atributo _CenterUv.
inserte la descripción de la imagen aquí

_CenterUv("裁剪中心",Vector)=(0.5,0.5,0,0)

3. La continuidad se congela gradualmente

En términos generales, UV tiene cierta continuidad. Aquí, un cierto punto en el mapa UV se puede usar como punto central y expandirse gradualmente hacia afuera para lograr el efecto de congelación gradual. El método de implementación específico es calcular la distancia entre el punto UV especificado y el punto de inicio, y aumentar gradualmente su valor para lograr el efecto.

//主图
half4 var_MainTex = tex2D(_MainTex, i.uv0);
//高光遮蔽图(用于区分哪部分有贴图内容)
half4 var_OcclusionTex = tex2D(_OcclusionTex, i.uv0);
//_CenterUv是指定中心,计算uv与中心点的距离,能修修改显示距离达到向外扩展效果
half dic =1- distance(i.uv0.xy, _CenterUv.xy)* var_OcclusionTex;
clip(dic- _ClipNum);

4. Carámbanos caídos

Necesitamos hacer un carámbano hacia abajo. Primero podemos usar el mapa de nubes para hacer efectos de perturbación aleatorios. El valor de color de estos efectos aleatorios suele ser 0-1. Aquí, solo la parte del patrón por encima de 0,45 puede formar carámbanos hacia abajo.
Para hacer que los carámbanos se vean más suaves, podemos usar la propiedad o.nDirWS.g en los vértices, que ajustará la coordenada Y de cada vértice según la distancia a la que caigan los carámbanos en la dirección.
Entonces, después de determinar el mapeo UV, debemos mover los vértices más de 0.45 hacia arriba en la distancia especificada, lo que dará como resultado una forma similar a un carámbano.
inserte la descripción de la imagen aquí

//在顶点阶段读图需要用tex2DLod(这里是云彩干扰图)
half h = tex2Dlod(_CloudTex, float4(v.uv0.xy, 0, 0)).r;
//读云彩图色值,红色值大于0.45的做法线扩展,用于做冰刺效果
//o.nDirWS.g 得到向下的法线,因为冰刺只要向下的 g 也相当于Y轴
half stepNormal = step(h,0.45)*_VectorNormalScale*max(0,(_VectorNormalScale - o.nDirWS.g));

5. Efecto semifluorescente

Por lo general, suele haber algún efecto irregular en la superficie del hielo. Podemos simular estos efectos usando texturas. Además, a veces la superficie del hielo tiene algunos efectos chispeantes. En este caso, podemos usar la luz de Fresnel para la simulación.
inserte la descripción de la imagen aquí

//光源漫反射
half3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
half3 baseCol = var_MainTex.rgb*ambient*_LightColor0;//
half lambert = max(0.0, ndotl);
//光源镜面反射
	half specPow = _SpecPow;
	half phong = pow(max(0.0,vdotr), _SpecPow);
	//光源反射混合
	half3 baseLighting = (baseCol  + phong * _EnvSpecInt);//(baseCol * lambert + phong * _EnvSpecInt)
	//环境漫反身
	half3 envDiff = baseCol * _EnvDiffInt;
	half upMask = max(0.0, nDirTSOrigin.g);
	//环境镜面反射
	half3 fresnel = pow(max(0.0, 1.0 - vdotn), _FresnelPow) * _FresnelInt*ambient.rgb;//菲涅尔
	half3 envSpec = fresnel * _EnvSpecInt*ambient;
	//环境反射混合
	half3 envLighting = (envDiff + envSpec)*ambient*_LightColor0;
	//最终混合
	half3 finalRGB = (baseLighting+envLighting + fresnel )* var_OcclusionTex.r;// ;*(1 - scale)

Sexto, el siguiente es el código completo:

Aquí está el código completo, puede combinar el código con la explicación anterior para comprenderlo mejor. También se puede expandir a más efectos, espero que sea de ayuda para todos, gracias.

Shader "Custom/IceAnimStandard" {
    
    
	Properties{
    
    
		   [Header(Ground_Base)]
				  _MainTex("基础色 ",2D) = "white"{
    
    }
				  _CloudTex("干扰图 ",2D) = "white"{
    
    }
				  _BaseColor("基础色",Color) = (1.0,1.0,1.0,1.0)
				  _NormMap("法线贴图",2D) = "bump"{
    
    }

		   [Header(Normal)]
				  _NormalScale("法线缩放",Range(0.0,1)) = 1
				  _VectorNormalScale("顶点法线缩放",Range(0,0.1)) = 0
				  _BaseVectorNormalScale("基础顶点法线缩放",Range(0,1)) = 0.06
		   [Header(Ground_Diffuse)]
				  _EnvDiffInt("环境漫反射强度",Range(0,1)) = 0.2
		   [Header(Ground_Specular)]
				  _FresnelPow("菲涅尔次幂",Range(0,10)) = 1
				  _FresnelInt("菲涅尔强度",Range(0,2)) = 1
				  _SpecPow("高光次幂",Range(0,5)) = 30
				  _EnvSpecInt("环境镜面反射强度",Range(0,5)) = 0.2

				  _OcclusionTex("高光遮蔽",2D) = "white"{
    
    }
				  _CenterUv("裁剪中心",Vector)=(0.5,0.5,0,0)
				  _ClipNum("裁剪数值",Range(0,1)) = 1
				  

	}
		SubShader{
    
    
			Tags{
    
    "RenderType" = "Opaque" "IgnoreProjector" = "True"}//

			Pass{
    
    
				Tags{
    
    "LightMode" = "ForwardBase"}
				//ZWrite off
				//Cull off
			CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				#include "Lighting.cginc"
				#include "AutoLight.cginc"
				#include "UnityCG.cginc"
				#pragma target 3.0
				#pragma multi_compile_fwdbase
					  //地面参数
					  uniform sampler2D _MainTex;
					  uniform sampler2D _CloudTex;
					  uniform sampler2D _NormMap; uniform half4 _NormMap_ST;
					  uniform half4 _BaseColor;
					  uniform half _NormalScale;
					  uniform half _VectorNormalScale;
					  uniform half _BaseVectorNormalScale;
					  uniform half _EnvDiffInt;
					  uniform half _SpecPow;
					  uniform half _EnvSpecInt;
					  uniform half _FresnelPow;
					  uniform half _FresnelInt;
					  uniform sampler2D _OcclusionTex;
					  uniform half2 _CenterUv;
					  uniform half _ClipNum;
					  


					  //输入结构
					  struct a2v {
    
    
						  float4 vertex:       POSITION;				//顶点信息
						  float2 uv0:          TEXCOORD0;				//UV信息
						  float4 normal:       NORMAL;					//法线信息
						  float4 tangent:      TANGENT;					//切线信息
					  };
					  //输出结构
					  struct v2f {
    
    
						  float4 pos:SV_POSITION;						//屏幕定点位置
						  float2 uv0:TEXCOORD0;						//UV(不可动)保持默认
						  float2 uv2:TEXCOORD2;						//法线UV(用于重复平铺)
						  float3 WorldPos:TEXCOORD7;						//世界坐标位置
						  float3 nDirWS:TEXCOORD4;					//世界坐标法线
						  float3 tDirWS:TEXCOORD5;					//世界坐标切线
						  float3 bDirWS:TEXCOORD6;					//世界坐标副切线
						  SHADOW_COORDS(3)
					  };
					  v2f vert(a2v v) {
    
    
						  v2f o;																			//新输出结构
						  o.nDirWS = UnityObjectToWorldNormal(v.normal);									//法线位置   OS>WS

						  half h = tex2Dlod(_CloudTex, float4(v.uv0.xy, 0, 0)).r;
						  half stepNormal = step(h,0.45)*_VectorNormalScale*max(0,(_VectorNormalScale - o.nDirWS.g));
						  
						  half4 downNormal = -half4(o.nDirWS,0);
						  downNormal.y = max(0.1, downNormal.y);
						  downNormal.x = 0;
						  downNormal.z = 0;
						  v.vertex += downNormal * stepNormal + _BaseVectorNormalScale*v.normal;
						  o.pos = UnityObjectToClipPos(v.vertex);											//顶点位置    OS>CS
						  o.uv0 = v.uv0;																	//传弟UV


						  o.uv2 = v.uv0 *_NormMap_ST.xy + _NormMap_ST.zw;																	//传弟UV


						  o.WorldPos = mul(unity_ObjectToWorld, v.vertex);								//点位置     CS>WS
						  o.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz,0)).xyz);    //切线方向
						  o.bDirWS = normalize(cross(o.nDirWS,o.tDirWS)*v.tangent.w);						//副切方向
						  TRANSFER_SHADOW(o);

						  return o;
					  }
					  float4 frag(v2f i) :SV_TARGET{
    
    


						  //纹理采样
						  half4 var_MainTex = tex2D(_MainTex, i.uv0);
						  half4 var_OcclusionTex = tex2D(_OcclusionTex, i.uv0);

						  half dic =1- distance(i.uv0.xy, _CenterUv.xy)* var_OcclusionTex;
						  clip(dic- _ClipNum);

						  var_MainTex.rgb *= _BaseColor;
							//向量准备
						  float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS);
						  float4 var_normapTex = tex2D(_NormMap,i.uv2);
							float3 nDirTS = UnpackNormal(var_normapTex).rgb;
							float3 nDirTSOrigin = normalize(mul(nDirTS, TBN));
							nDirTS.xy *= (_NormalScale - (abs(i.uv0.y - 0.5)*(_NormalScale)));
							nDirTS.z = max(0.5, sqrt(1.0 - saturate(dot(var_normapTex.xy, var_normapTex.xy))));


							float3 nDirWS = normalize(mul(nDirTS, TBN));
							float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.WorldPos.xyz);
							float3 lDirWS = _WorldSpaceLightPos0.xyz;
							float3 lrDirWS = reflect(-lDirWS,nDirWS);
							//中间量准备
							float ndotl = max(0.5, dot(nDirWS, lDirWS));
							float vdotr = dot(vDirWS, lrDirWS);
							float vdotn = dot(vDirWS, nDirWS);

							//光照模型
								   //光源漫反射
								   half3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;
								   half3 baseCol = var_MainTex.rgb*ambient*_LightColor0;//
								   half lambert = max(0.0, ndotl);
								   //光源镜面反射
								   half specPow = _SpecPow;
								   half phong = pow(max(0.0,vdotr), _SpecPow);
								   //光源反射混合
								   half3 baseLighting = (baseCol  + phong * _EnvSpecInt);//(baseCol * lambert + phong * _EnvSpecInt)
								   //环境漫反身
								   half3 envDiff = baseCol * _EnvDiffInt;
								   half upMask = max(0.0, nDirTSOrigin.g);
								   //环境镜面反射
								   half3 fresnel = pow(max(0.0, 1.0 - vdotn), _FresnelPow) * _FresnelInt*ambient.rgb;//菲涅尔
								   half3 envSpec = fresnel * _EnvSpecInt*ambient;
								   //环境反射混合
								   half3 envLighting = (envDiff + envSpec)*ambient*_LightColor0;
								   //最终混合
								   half3 finalRGB = (baseLighting+envLighting + fresnel )* var_OcclusionTex.r;// ;*(1 - scale)
								   //返回值

								   //阴影衰减
								   UNITY_LIGHT_ATTENUATION(atten, i, i.WorldPos);

								   return half4((finalRGB)*atten,1);
					  }
				  ENDCG
			  }

				  }
					  FallBack "Diffuse"
}

Supongo que te gusta

Origin blog.csdn.net/ww1351646544/article/details/126994099
Recomendado
Clasificación