shader入门精要读书笔记43 使用噪声纹理的非均匀雾效

一、思路

仍然需要屏幕后处理效果,和之前的雾效果实现基本一样(全局雾效计算),就是多算了一个噪声值混合雾效果的浓度 用来插值原始颜色和雾颜色。

二、具体实现代码:

摄像机脚本代码:

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;			//噪声纹理在x、y轴的飘动速度

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

	[Range(0.0f, 3.0f)]
	public float noiseAmount = 1.0f;				//噪声程度,0的话就不应用噪声纹理,

	void OnEnable() {
		GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;			//设置摄像机模式
	}
		
	void OnRenderImage (RenderTexture src, RenderTexture dest) {			//屏幕处理函数
		if (material != null) {
			Matrix4x4 frustumCorners = Matrix4x4.identity;			//存储近裁剪平面的4个角对应的变量
			
			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);			//传入Shader中

			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);
		}
	}
}

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;			
			//采样噪声纹理,-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
}

三、以上所有的噪声纹理是如何被制作出来的

噪声纹理也可以被认为是一种程序纹理,他们都是由计算机利用某些算法生成的,

Perlin噪声和Worley噪声是最常用的两种噪声。

Perlin噪声是可以用来生成一些比较自然的纹理,
Worley噪声通常用来模拟诸如石头、水、纸张等多孔噪声。

现在的很多软件,都提供了类似功能插件,用来帮助美术人员生成需要的噪声纹理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值