要想通过屏幕后期处理效果实现高度雾,就得知道屏幕中每个像素在世界空间中的坐标。
其中一种方法是:
打开深度纹理,通过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; } }
子类
using UnityEngine; public class HighFog : PostEffectRenderer { protected override string ShaderName { get { return "Custom/Study/High Fog"; } } void OnEnable() { base.SelfCamera.depthTextureMode = DepthTextureMode.Depth; } void OnDisable() { base.SelfCamera.depthTextureMode = DepthTextureMode.None; } protected override void OnRenderImage(RenderTexture src, RenderTexture dest) { var projMatrix = GL.GetGPUProjectionMatrix(base.SelfCamera.projectionMatrix, false); var m = projMatrix * base.SelfCamera.worldToCameraMatrix; base.Mat.SetMatrix("_ViewportToWorldMatrix", m.inverse); base.OnRenderImage(src, dest); } }
shader
Shader "Custom/Study/High Fog" { Properties { _MainTex ("Texture", 2D) = "white" {} _FogColor ("Color", Color) = (1, 1, 1, 1) _FogPosY ("Fog pos y", float) = 0.1 _FogDisappearHeight ("Fog disappear height", float) = 10 } SubShader { Pass { ZTest Always ZWrite Off Cull Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; sampler2D _CameraDepthTexture; uniform float4x4 _ViewportToWorldMatrix; float4 _FogColor; float _FogPosY; float _FogDisappearHeight; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv); float4 H = float4(i.uv.x * 2 - 1, i.uv.y * 2 - 1, d, 1); float4 D = mul(_ViewportToWorldMatrix, H); float4 worldPos = D / D.w; float fogWeight; if(worldPos.y < _FogPosY) { fogWeight = 1; } else if(worldPos.y > _FogPosY + _FogDisappearHeight) { fogWeight = 0; } else { fogWeight = 1 - (worldPos.y - _FogPosY) / _FogDisappearHeight; } return lerp(col, _FogColor, fogWeight); } ENDCG } } Fallback Off }
效果如下图: