Unity Shader 学习笔记(28) 噪声纹理、消融效果、水波效果、噪声雾效

44 篇文章 5 订阅
36 篇文章 5 订阅

Unity Shader 学习笔记(28) 噪声纹理、消融效果、水波效果、噪声雾效

参考书籍:《Unity Shader 入门精要》


噪声纹理

通过纹理深浅可以作为一些变换的阈值,或者透明度等。
在这里插入图片描述


消融效果(Dissolve)

常用与角色死亡、地图烧毁时效果。

Burn Amount从0变化到1。
在这里插入图片描述

Properties {
	_BurnAmount ("Burn Amount", Range(0.0, 1.0)) = 0.0				// 消融程度 0为正常效果
	_LineWidth("Burn Line Width", Range(0.0, 0.2)) = 0.1			// 消融效果时的线宽
	_MainTex ("Base (RGB)", 2D) = "white" {}						// 漫反射纹理
	_BumpMap ("Normal Map", 2D) = "bump" {}							// 法线纹理
	_BurnFirstColor("Burn First Color", Color) = (1, 0, 0, 1)		// 火焰边缘颜色值
	_BurnSecondColor("Burn Second Color", Color) = (1, 0, 0, 1)
	_BurnMap("Burn Map", 2D) = "white"{}							// 噪声纹理
}
SubShader {
	Tags { "RenderType"="Opaque" "Queue"="Geometry"}
	
	Pass {
		Tags { "LightMode"="ForwardBase" }

		Cull Off	// 关掉剔除,正反面都渲染
		
		...
		
		fixed4 frag(v2f i) : SV_Target {
			...

			fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;
			clip(burn.r - _BurnAmount);		// 如果小于0,该像素会被剔除

			//_LineWidth宽度范围模拟渐变。t为0是正常颜色,为1时位于消融的边界
			fixed t = 1 - smoothstep(0.0, _LineWidth, burn.r - _BurnAmount);
			fixed3 burnColor = lerp(_BurnFirstColor, _BurnSecondColor, t);	//两个烧焦颜色做插值
			burnColor = pow(burnColor, 5);	// 加强颜色模拟烧焦痕迹
			
			UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
			fixed3 finalColor = lerp(ambient + diffuse * atten, burnColor, t * step(0.0001, _BurnAmount));
			
			return fixed4(finalColor, 1);
		}
		ENDCG
	}
	
	// 阴影投射,直接剔除掉阈值内的像素即可
	Pass {
		Tags { "LightMode" = "ShadowCaster" }
		
		...
		
		fixed4 frag(v2f i) : SV_Target {
			fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;
			
			clip(burn.r - _BurnAmount);		// 剔除掉透明的
			
			SHADOW_CASTER_FRAGMENT(i)
		}
		ENDCG
	}
}

水波效果

噪声作为高度图,修改水面法线。使用Schilick菲涅尔反射实现:fresnel = pow(1 - max(0, v·n),4 )

菲涅尔动态水面效果:
在这里插入图片描述

Properties {
	_Color ("Main Color", Color) = (0, 0.15, 0.115, 1)
	_MainTex ("Base (RGB)", 2D) = "white" {}
	_WaveMap ("Wave Map", 2D) = "bump" {}							// 噪声法线纹理
	_Cubemap ("Environment Cubemap", Cube) = "_Skybox" {}			// 立方体纹理
	_WaveXSpeed ("Wave Horizontal Speed", Range(-0.1, 0.1)) = 0.01	// 法线平移速度
	_WaveYSpeed ("Wave Vertical Speed", Range(-0.1, 0.1)) = 0.01
	_Distortion ("Distortion", Range(0, 100)) = 10					// 折射扭曲度
}
SubShader {
	// 所有不透明物体渲染完后
	Tags { "Queue"="Transparent" "RenderType"="Opaque" }
	
	// 抓取屏幕Pass 存入_RefractionTex 
	GrabPass { "_RefractionTex" }
	
	Pass {
		...
		
		#pragma multi_compile_fwdbase
		
		...
		sampler2D _RefractionTex;				// 对应GrabPass
		float4 _RefractionTex_TexelSize;
		...
		
		v2f vert(a2v v) {
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);
			
			o.scrPos = ComputeGrabScreenPos(o.pos);			// 抓取屏幕图像的采样坐标
			
			...// 计算世界空间下切线法线等,构造转换矩阵
			
			return o;
		}
		
		fixed4 frag(v2f i) : SV_Target {
			float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
			fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
			float2 speed = _Time.y * float2(_WaveXSpeed, _WaveYSpeed);
			
			// 对法线两次采样(模拟两层交叉水面波动),相加得到切线空间下的法线方向。
			fixed3 bump1 = UnpackNormal(tex2D(_WaveMap, i.uv.zw + speed)).rgb;
			fixed3 bump2 = UnpackNormal(tex2D(_WaveMap, i.uv.zw - speed)).rgb;
			fixed3 bump = normalize(bump1 + bump2);
			
			// 计算偏移量,切线空间
			float2 offset = bump.xy * _Distortion * _RefractionTex_TexelSize.xy;
			i.scrPos.xy = offset * i.scrPos.z + i.scrPos.xy;			// offset * i.scrPos.z 模拟水越深,折射越大
			fixed3 refrCol = tex2D( _RefractionTex, i.scrPos.xy/i.scrPos.w).rgb;
			
			// 计算法线到世界空间
			bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));
			fixed4 texColor = tex2D(_MainTex, i.uv.xy + speed);
			fixed3 reflDir = reflect(-viewDir, bump);
			fixed3 reflCol = texCUBE(_Cubemap, reflDir).rgb * texColor.rgb * _Color.rgb;

			// Schilick菲涅尔近似等式
			fixed fresnel = pow(1 - saturate(dot(viewDir, bump)), 4);
			fixed3 finalColor = reflCol * fresnel + refrCol * (1 - fresnel);
			
			return fixed4(finalColor, 1);
		}
		
		ENDCG
	}
}

噪声雾效

前面实现过雾效在同一高度的浓度是一致的,这里使用噪声模拟雾的浓度,实现非均匀雾效。
在这里插入图片描述

在这里插入图片描述

在之前实现的雾效添加一些属性。

Properties {
	_MainTex ("Base (RGB)", 2D) = "white" {}
	_FogDensity ("Fog Density", Float) = 1.0
	_FogColor ("Fog Color", Color) = (1, 1, 1, 1)
	_FogStart ("Fog Start", Float) = 0.0
	_FogEnd ("Fog End", Float) = 1.0
	_NoiseTex ("Noise Texture", 2D) = "white" {}		// 噪声纹理
	_FogXSpeed ("Fog Horizontal Speed", Float) = 0.1
	_FogYSpeed ("Fog Vertical Speed", Float) = 0.1
	_NoiseAmount ("Noise Amount", Float) = 1			// 噪声数量,0为不使用噪声
}
fixed4 frag(v2f i) : SV_Target {
	float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth));
	float3 worldPos = _WorldSpaceCameraPos + linearDepth * i.interpolatedRay.xyz;
	
	float2 speed = _Time.y * float2(_FogXSpeed, _FogYSpeed);
	float noise = (tex2D(_NoiseTex, i.uv + speed).r - 0.5) * _NoiseAmount;	// 随时间偏移雾效,-0.5是把范围控制在[-0.5,0.5]
			
	float fogDensity = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart); 
	fogDensity = saturate(fogDensity * _FogDensity * (1 + noise));	// (1 + noise):浓度倍数范围在[0.5, 1.5]内。
	
	fixed4 finalColor = tex2D(_MainTex, i.uv);
	finalColor.rgb = lerp(finalColor.rgb, _FogColor.rgb, fogDensity);
	
	return finalColor;
}
  • 5
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值