要想通过屏幕后期处理效果实现高度雾,就得知道屏幕中每个像素在世界空间中的坐标。
其中一种方法是:
打开深度纹理,通过uv坐标和深度计算出屏幕中每个像素在NDC中的坐标,再通过世界坐标到投影空间的转换矩阵的逆矩阵来变换,即可得到其在世界空间中的坐标。
但此种方法需要在 fragment shader 中进行矩阵乘法计算,而这通常会影响游戏性能。
转载请注明出处:https://www.cnblogs.com/jietian331/p/9441440.html
c#代码:
using UnityEngine; [RequireComponent(typeof(Camera))] public abstract class PostEffectRenderer : GameBehaviour { [SerializeField] Material m_material; Camera m_camera; protected abstract string ShaderName { get; } protected Material Mat { get { if (!m_material) { Shader shader = Shader.Find(ShaderName); if (shader != null && shader.isSupported) m_material = new Material(shader); else NotSupport(); } return m_material; } } protected Camera SelfCamera { get { if (!m_camera) m_camera = GetComponent<Camera>(); return m_camera; } } void Start() { if (!SystemInfo.supportsImageEffects) NotSupport(); } protected virtual void OnRenderImage(RenderTexture src, RenderTexture dest) { Graphics.Blit(src, dest, Mat); } protected void NotSupport() { Debug.LogError(string.Format("{0} not support!", this.GetType().Name)); enabled = false; } }
1 using UnityEngine; 2 3 public class HighFog : PostEffectRenderer 4 { 5 [SerializeField] 6 Color m_fogColor = Color.white; 7 [Range(0f, 1f)] 8 [SerializeField] 9 float m_fogDensity = 1; 10 [SerializeField] 11 float m_fogPosY = 0.1f; 12 [SerializeField] 13 float m_fogDisappearHeight = 10; 14 15 16 protected override string ShaderName 17 { 18 get { return "Custom/Study/High Fog"; } 19 } 20 21 void OnEnable() 22 { 23 base.SelfCamera.depthTextureMode = DepthTextureMode.Depth; 24 } 25 26 void OnDisable() 27 { 28 base.SelfCamera.depthTextureMode = DepthTextureMode.None; 29 } 30 31 protected override void OnRenderImage(RenderTexture src, RenderTexture dest) 32 { 33 var projMatrix = GL.GetGPUProjectionMatrix(base.SelfCamera.projectionMatrix, false); 34 var m = projMatrix * base.SelfCamera.worldToCameraMatrix; 35 base.Mat.SetMatrix("_ViewportToWorldMatrix", m.inverse); 36 base.Mat.SetColor("_FogColor", m_fogColor); 37 base.Mat.SetFloat("_FogDensity", m_fogDensity); 38 base.Mat.SetFloat("_FogPosY", m_fogPosY); 39 base.Mat.SetFloat("_FogDisappearHeight", m_fogDisappearHeight); 40 base.OnRenderImage(src, dest); 41 } 42 }
shader:
1 Shader "Custom/Study/High Fog" 2 { 3 Properties 4 { 5 _MainTex ("Texture", 2D) = "white" {} 6 } 7 8 SubShader 9 { 10 Pass 11 { 12 ZTest Always 13 ZWrite Off 14 Cull Off 15 16 CGPROGRAM 17 #pragma vertex vert 18 #pragma fragment frag 19 20 #include "UnityCG.cginc" 21 22 struct appdata 23 { 24 float4 vertex : POSITION; 25 float2 uv : TEXCOORD0; 26 }; 27 28 struct v2f 29 { 30 float2 uv : TEXCOORD0; 31 float4 vertex : SV_POSITION; 32 }; 33 34 sampler2D _MainTex; 35 sampler2D _CameraDepthTexture; 36 uniform float4x4 _ViewportToWorldMatrix; 37 uniform float4 _FogColor; 38 uniform float _FogDensity; 39 uniform float _FogPosY; 40 uniform float _FogDisappearHeight; 41 42 v2f vert (appdata v) 43 { 44 v2f o; 45 o.vertex = UnityObjectToClipPos(v.vertex); 46 o.uv = v.uv; 47 return o; 48 } 49 50 fixed4 frag (v2f i) : SV_Target 51 { 52 fixed4 col = tex2D(_MainTex, i.uv); 53 54 float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv); 55 float4 H = float4(i.uv.x * 2 - 1, i.uv.y * 2 - 1, d, 1); 56 float4 D = mul(_ViewportToWorldMatrix, H); 57 float4 worldPos = D / D.w; 58 59 float fogWeight; 60 if(worldPos.y < _FogPosY) 61 { 62 fogWeight = 1; 63 } 64 else if(worldPos.y > _FogPosY + _FogDisappearHeight) 65 { 66 fogWeight = 0; 67 } 68 else 69 { 70 fogWeight = 1 - (worldPos.y - _FogPosY) / _FogDisappearHeight; 71 } 72 73 return lerp(col, _FogColor, fogWeight * _FogDensity); 74 } 75 76 ENDCG 77 } 78 } 79 80 Fallback Off 81 }
效果如下图: