1. 程式人生 > 程式設計 >Unity Shader實現動態霧效果

Unity Shader實現動態霧效果

Unity Shader學習:動態霧,供大家參考,具體內容如下

先將相機近裁面四個角向量傳給shader,再通過觀察空間下的深度值和相機位置算出畫素在世界座標系的位置,通過世界空間高度值來設定霧的範圍和濃度,然後通過噪聲和uv偏移實現擾動效果。得到了類似寂靜嶺或惡靈附身1的效果。

Unity Shader實現動態霧效果

Unity Shader實現動態霧效果

C#部分:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
public class RayMarchingCamera : MonoBehaviour {
 private Matrix4x4 frustumCorners = Matrix4x4.identity;
 public Material material;
 public Camera myCamera;
 public Transform cameraTransform;
 // Use this for initialization
 private void Start()
 {
  myCamera.depthTextureMode = DepthTextureMode.Depth;
 }

 private void OnRenderImage(RenderTexture source,RenderTexture destination)
 {
  //field of view
  float fov = myCamera.fieldOfView;
  //近裁面距離
  float near = myCamera.nearClipPlane;
  //橫縱比
  float aspect = myCamera.aspect;
  //近裁面一半的高度
  float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
  //向上和向右的向量
  Vector3 toRight = myCamera.transform.right * halfHeight * aspect;
  Vector3 toTop = myCamera.transform.up * halfHeight;

  //分別得到相機到近裁面四個角的向量
  //depth/dist=near/|topLeft|
  //dist=depth*(|TL|/near)
  //scale=|TL|/near
  Vector3 topLeft = cameraTransform.forward * near + toTop - toRight;
  float scale = topLeft.magnitude / near;

  topLeft.Normalize();
  topLeft *= scale;

  Vector3 topRight = cameraTransform.forward * near + toTop + toRight;
  topRight.Normalize();
  topRight *= scale;

  Vector3 bottomLeft = cameraTransform.forward * near - toTop - toRight;
  bottomLeft.Normalize();
  bottomLeft *= scale;

  Vector3 bottomRight = cameraTransform.forward * near - toTop + toRight;
  bottomRight.Normalize();
  bottomRight *= scale;

  //給矩陣賦值
  frustumCorners.SetRow(0,bottomLeft);
  frustumCorners.SetRow(1,bottomRight);
  frustumCorners.SetRow(2,topRight);
  frustumCorners.SetRow(3,topLeft);
  //將向量傳給定點著色器,將螢幕畫面傳個shader
  material.SetMatrix("_FrustumCornorsRay",frustumCorners);
  material.SetTexture("_MainTex",source);
  Graphics.Blit(source,destination,material,0);
 }
}

shader部分:

Shader "Unlit/Fog"
{
 Properties
 {
 _MainTex ("Texture",2D) = "white" {}
 _NoiseTex("NoiseTex",2D)="white"{}
 //霧起始高度
 _FogStartHeight("FogStartHeight",float)=0.0
 //霧終點高度
 _FogEndHeight("FogEndHeight",float)=1.0
 //霧x位移速度
 _FogXSpeed("FogXSpeed",float)=0.1
 //霧y位移速度
 _FogYSpeed("FogYSpeed",float)=0.1
 }
 SubShader
 {
 Tags { "RenderType"="Opaque" }
 LOD 100

 Pass
 {
 CGPROGRAM
 #pragma vertex vert
 #pragma fragment frag
 #include "UnityCG.cginc"
 sampler2D _MainTex;
 sampler2D _NoiseTex;
 sampler2D _CameraDepthTexture;
 float _FogStartHeight;
 float _FogEndHeight;
 float _FogXSpeed;
 float _FogYSpeed;
 //獲得相機近裁面四個角向量
 float4x4 _FrustumCornorsRay;

 struct a2v{
 float4 vertex:POSITION;
 float2 uv:TEXCOORD0;
 };

 struct v2f{
 float4 pos:SV_POSITION;
 float2 uv:TEXCOORD0;
 float4 interpolatedRay:TEXCOORD1;
 };

 v2f vert(a2v v){
 v2f o;
 o.pos=UnityObjectToClipPos(v.vertex);
 o.uv=v.uv;
 int index=0;
 if (v.uv.x<0.5&&v.uv.y<0.5)
 {
  index = 0;
 }
 else if (v.uv.x>0.5&&v.uv.y<0.5) {
  index = 1;
 }
 else if (v.uv.x>0.5&&v.uv.y>0.5) {
  index = 2;
 }
 else {
  index = 3;
 }
 //安排uv4個角對應四個角向量
 o.interpolatedRay = _FrustumCornorsRay[index];
 return o;
 }

 float4 frag(v2f i):SV_Target{
 //觀察空間下的線性深度值
 float linearDepth=LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv));
 //畫素世界座標=世界空間相機位置+畫素相對相機距離
 float3 worldPos=_WorldSpaceCameraPos+linearDepth*i.interpolatedRay.xyz;
 float speedX=_Time.y*_FogXSpeed;
 float speedY=_Time.y*_FogYSpeed;
 float noise=tex2D(_NoiseTex,i.uv+float2(speedX,speedY));
 //讓噪聲圖向黑色靠攏,黑白差距不要太大
 noise=pow(noise,0.5);
 //霧濃度=世界高度/指定範圍
 float fogDensity=(_FogEndHeight-worldPos.y)/(_FogEndHeight-_FogStartHeight);
 fogDensity=smoothstep(0.0,1.0,fogDensity*noise);
 float4 color=tex2D(_MainTex,i.uv);
 //根據霧濃度混合場景和霧顏色
 color.rgb=lerp(color.rgb,float3(0.5,0.5,0.5),fogDensity);
 return color;
 }

 ENDCG
 }
 }
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。