【Shader入门精要】第十五章——使用噪声

一、消融效果

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "MilkShader/15/Dissolve"
{
	Properties
	{		
		//控制消融程度: 0 为正常效果, 为1会完全消融
		_BurnAmount ("Burn Amount", Range(0.0, 1.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"}
		Cull Off

		Pass
		{
			Tags { "LightMode" = "ForwardBase" }
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag			
			#pragma multi_compile_fwdbase
			
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "AutoLight.cginc"

			struct appdata
			{
				float4 vertex : POSITION;
				float3 normal : NORMAL;
				float4 tangent : TANGENT;
				float2 texcoord : TEXCOORD0;
			};

			struct v2f
			{				
				float4 pos : SV_POSITION;
				float2 uvMainTex : TEXCOORD0;
				float2 uvBumpMap : TEXCOORD1;
				float2 uvBurnMap: TEXCOORD2;
				float3 lightDir : TEXCOORD3;
				float3 worldPos : TEXCOORD4;
				SHADOW_COORDS(5)
			};

			fixed _BurnAmount;
			fixed _LineWidth;
			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _BumpMap;
			float4 _BumpMap_ST;
			fixed4 _BurnFirstColor;
			fixed4 _BurnSecondColor;
			sampler2D _BurnMap;
			float4 _BurnMap_ST;
			
			v2f vert (appdata v)
			{
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uvMainTex = TRANSFORM_TEX(v.texcoord, _MainTex);
				o.uvBumpMap = TRANSFORM_TEX(v.texcoord, _BumpMap);
				o.uvBurnMap = TRANSFORM_TEX(v.texcoord, _BurnMap);
				
				TANGENT_SPACE_ROTATION;
				o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;

				TRANSFER_SHADOW(o);

				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;

				clip(burn.r - _BurnAmount);

				fixed3 tangentLightDir = normalize(i.lightDir);
				fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap, i.uvBumpMap));

				fixed3 albedo = tex2D(_MainTex, i.uvMainTex).rgb;
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;

				fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentNormal, tangentLightDir));
				
				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"
			}
			CGPROGRAM

			#include "UnityCG.cginc" //下面三个宏都是这个文件中的

			#pragma vertex vert
			#pragma fragment frag

			#pragma multi_compile_shadowcaster

			sampler2D _BurnMap;
			float4 _BurnMap_ST;
			fixed _BurnAmount;

			struct v2f{
				//阴影计算的变量
				V2F_SHADOW_CASTER;
				//噪声纹理坐标
				float2 uvBurnMap : TEXCOORD1;
			};

			v2f vert(appdata_base v){
				v2f o;
				//计算并赋值阴影的变量(在顶点输入变量appdata_base中拥有vertex和normal进行计算阴影,并且变量名必须是v,计算结果会存入o的阴影变量中)
				//TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
				TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
					
				o.uvBurnMap = TRANSFORM_TEX(v.texcoord, _BurnMap);

				return o;
			}

			fixed4 frag(v2f i):SV_Target{
				//裁剪
				fixed3 burn = tex2D(_BurnMap, i.uvBurnMap).rgb;
				clip(burn.r - _BurnAmount);
				//阴影计算输出到深度图和阴影映射图
				SHADOW_CASTER_FRAGMENT(i)
			}
			ENDCG
		}
	}
	FallBack "Diffuse"
}

二、水波纹效果

原理:环境反射和折射

// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'

Shader "MilkShader/15/WaterWave"
{
	Properties
	{
		_Color("Color", Color) = (0, 0.15, 0.115, 1)
		_MainTex ("Texture", 2D) = "white" {}
		_WaveMap("Wave Map", 2D) = "bump"{}
		_Cubemap("Env CubeMap", Cube) = "_Skybox"{}
		_WaveXSpeed("Wave H Speed", Range(-0.1, 0.1)) = 0.01
		_WaveYSpeed("Wave V Speed", Range(-0.1 ,0.1)) = 0.01
		_Distortion("Distortion", Range(0, 100)) = 10
	}
		SubShader
		{
			Tags { "Queue" = "Transparent" "RenderType" = "Opaque" }

			GrabPass { "_RefractionTex"}


			LOD 100

			Pass
			{
				Tags{"LightMode" = "ForwardBase"}
				CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
			
				#pragma multi_compile_fwdbase

				#include "UnityCG.cginc"
				#include "Lighting.cginc"
				
				fixed4 _Color;
				sampler2D _MainTex;
				float4 _MainTex_ST;
				sampler2D _WaveMap;
				float4 _WaveMap_ST;
				samplerCUBE _Cubemap;
				fixed _WaveXSpeed;
				fixed _WaveYSpeed;
				float _Distortion;
				sampler2D _RefractionTex;
				float4 _RefractionTex_TexelSize;

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

				struct v2f
				{
					float4 pos : SV_POSITION;
					float4 srcPos : TEXCOORD0;
					float4 uv : TEXCOORD1;
					float4 TtoW0 : TEXCOORD2;
					float4 TtoW1 : TEXCOORD3;
					float4 TtoW2 : TEXCOORD4;

				};

			
				v2f vert (appdata v)
				{
					v2f o;
					o.pos = UnityObjectToClipPos(v.vertex);
					o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
					o.uv.zw = TRANSFORM_TEX(v.uv, _WaveMap);
					o.srcPos = ComputeGrabScreenPos(o.pos);

					float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
					fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
					fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
					fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;

					o.TtoW0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
					o.TtoW1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
					o.TtoW2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);

					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.srcPos.xy = offset * i.srcPos.z + i.srcPos.xy;

					fixed3 refrCol = tex2D(_RefractionTex, i.srcPos.xy / i.srcPos.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;

					fixed fresnel = pow(1 - saturate(dot(viewDir, bump)), 4);
					fixed3 finalCol = reflCol * fresnel + refrCol * (1 - fresnel);

					return fixed4(finalCol, 1);
				}
				ENDCG
			}
		}
}

这个渲染的对象是一个Plane物体

三、混入噪声的雾效

1、摄像机物体身上的脚本:

using UnityEngine;
using System.Collections;

public class FogWithNoise : PostEffectsBase {

	public Shader fogShader;
	private Material fogMaterial = null;

	public Material material {  
		get {
			fogMaterial = CheckShaderAndCreateMaterial(fogShader, fogMaterial);
			return fogMaterial;
		}  
	}
	
	private Camera myCamera;
	public Camera camera {
		get {
			if (myCamera == null) {
				myCamera = GetComponent<Camera>();
			}
			return myCamera;
		}
	}

	private Transform myCameraTransform;
	public Transform cameraTransform {
		get {
			if (myCameraTransform == null) {
				myCameraTransform = camera.transform;
			}
			
			return myCameraTransform;
		}
	}

	[Range(0.1f, 3.0f)]
	public float fogDensity = 1.0f;

	public Color fogColor = Color.white;

	public float fogStart = 0.0f;
	public float fogEnd = 2.0f;

	public Texture noiseTexture;

	[Range(-0.5f, 0.5f)]
	public float fogXSpeed = 0.1f;

	[Range(-0.5f, 0.5f)]
	public float fogYSpeed = 0.1f;

	[Range(0.0f, 3.0f)]
	public float noiseAmount = 1.0f;

	void OnEnable() {
		GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;
	}
		
	void OnRenderImage (RenderTexture src, RenderTexture dest) {
		if (material != null) {
			Matrix4x4 frustumCorners = Matrix4x4.identity;
			
			float fov = camera.fieldOfView;
			float near = camera.nearClipPlane;
			float aspect = camera.aspect;
			
			float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
			Vector3 toRight = cameraTransform.right * halfHeight * aspect;
			Vector3 toTop = cameraTransform.up * halfHeight;
			
			Vector3 topLeft = cameraTransform.forward * near + toTop - toRight;
			float scale = topLeft.magnitude / near;
			
			topLeft.Normalize();
			topLeft *= scale;
			
			Vector3 topRight = cameraTransform.forward * near + toRight + toTop;
			topRight.Normalize();
			topRight *= scale;
			
			Vector3 bottomLeft = cameraTransform.forward * near - toTop - toRight;
			bottomLeft.Normalize();
			bottomLeft *= scale;
			
			Vector3 bottomRight = cameraTransform.forward * near + toRight - toTop;
			bottomRight.Normalize();
			bottomRight *= scale;
			
			frustumCorners.SetRow(0, bottomLeft);
			frustumCorners.SetRow(1, bottomRight);
			frustumCorners.SetRow(2, topRight);
			frustumCorners.SetRow(3, topLeft);
			
			material.SetMatrix("_FrustumCornersRay", frustumCorners);

			material.SetFloat("_FogDensity", fogDensity);
			material.SetColor("_FogColor", fogColor);
			material.SetFloat("_FogStart", fogStart);
			material.SetFloat("_FogEnd", fogEnd);

			material.SetTexture("_NoiseTex", noiseTexture);
			material.SetFloat("_FogXSpeed", fogXSpeed);
			material.SetFloat("_FogYSpeed", fogYSpeed);
			material.SetFloat("_NoiseAmount", noiseAmount);

			Graphics.Blit (src, dest, material);
		} else {
			Graphics.Blit(src, dest);
		}
	}
}

2、Fog Shader 渲染雾的Shader:

原理:从噪声纹理随机采样出的噪声值作为雾浓度的强度系数进行模拟更逼真的雾效果

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unity Shaders Book/Chapter 15/Fog With Noise" {
	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
	}
	SubShader {
		CGINCLUDE
		
		#include "UnityCG.cginc"
		
		float4x4 _FrustumCornersRay;
		
		sampler2D _MainTex;
		half4 _MainTex_TexelSize;
		sampler2D _CameraDepthTexture;
		half _FogDensity;
		fixed4 _FogColor;
		float _FogStart;
		float _FogEnd;
		sampler2D _NoiseTex;
		half _FogXSpeed;
		half _FogYSpeed;
		half _NoiseAmount;
		
		struct v2f {
			float4 pos : SV_POSITION;
			float2 uv : TEXCOORD0;
			float2 uv_depth : TEXCOORD1;
			float4 interpolatedRay : TEXCOORD2;
		};
		
		v2f vert(appdata_img v) {
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);
			
			o.uv = v.texcoord;
			o.uv_depth = v.texcoord;
			
			#if UNITY_UV_STARTS_AT_TOP
			if (_MainTex_TexelSize.y < 0)
				o.uv_depth.y = 1 - o.uv_depth.y;
			#endif
			
			int index = 0;
			if (v.texcoord.x < 0.5 && v.texcoord.y < 0.5) {
				index = 0;
			} else if (v.texcoord.x > 0.5 && v.texcoord.y < 0.5) {
				index = 1;
			} else if (v.texcoord.x > 0.5 && v.texcoord.y > 0.5) {
				index = 2;
			} else {
				index = 3;
			}
			#if UNITY_UV_STARTS_AT_TOP
			if (_MainTex_TexelSize.y < 0)
				index = 3 - index;
			#endif
			
			o.interpolatedRay = _FrustumCornersRay[index];
				 	 
			return o;
		}
		
		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;
					
			float fogDensity = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart); 
			fogDensity = saturate(fogDensity * _FogDensity * (1 + noise));
			
			fixed4 finalColor = tex2D(_MainTex, i.uv);
			finalColor.rgb = lerp(finalColor.rgb, _FogColor.rgb, fogDensity);
			
			return finalColor;
		}
		
		ENDCG
		
		Pass {          	
			CGPROGRAM  
			
			#pragma vertex vert  
			#pragma fragment frag  
			  
			ENDCG
		}
	} 
	FallBack Off
}

噪声纹理:

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要理解shader入门精要,首先需要了解shader是指令代码,需要关联材质才能赋予游戏对象以特定的效果。材质按照关联的shader的规则,处理贴图等输入信息,达到特定的画面效果。 在Unity中,有几种类型的shader可供选择。一种是表面着色器(Surface Shader),它是对顶点/片断着色器的封装,更符合人类的思维模式,可以以极少的代码来实现不同的光照模型和不同平台下的需求。在表面着色器的开发中,我们直接在Subshader层次上编写代码,系统会将代码编译成适当的Pass。而顶点/片断着色器是更基础的shader类型,能够实现更多的效果,但表面着色器不一定能实现这些效果。还有一种被淘汰的固定管线着色器(Fixed Function Shaders),它在硬件上执行基本的命令,速度很快,但功能有限,不再推荐使用。 不同图形API都有各自的shader语言。在DirectX中,顶点shader叫做Vertex Shader,像素shader叫做Pixel Shader。而在OpenGL中,顶点shader也叫做Vertex Shader,但像素shader叫做Fragment Shader或者片断Shader。这些shader语言有不同的语法和特性,需要根据使用的图形API选择适当的语言来编写shader。 总结起来,要入门shader,首先需要了解shader是指令代码,需要关联材质才能实现效果。在Unity中,可以选择使用表面着色器、顶点/片断着色器或固定管线着色器来实现不同的效果。此外,不同图形API有不同的shader语言,需要根据使用的API选择合适的语言来编写shader
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值