后处理 - 简单雾效

基于高度的雾

 

 原理

就是计算当前高度时雾的权重:fogWeight=(FogMaxY - CurY) / FogHeight,然后根据权重显示贴图颜色和雾颜色。所以,Y值越小雾越浓,Y值越大雾越淡。

 

usin UnityEngine;

[RequireComponent(typeof(Camera))]
public class PostEffectHeightFog : MonoBehaviour
{
    private Camera m_Camera;
    private Material m_FogMat;
    private Matrix4x4 m_ClipToWorldMatrix;

    [Range(0.01f, 3)]
    public float m_FogStrength = 0.3f;
    public Color m_FogColor = Color.white;
    public float m_FogStart = 0;
    [Min(0.01f)]
    public float m_FogHeight = 1;

    void Start()
    {
        m_Camera = GetComponent<Camera>();
        m_FogMat = new Material(Shader.Find("My/DepthTex/HeightFog"));

        var VPMatrix = m_Camera.projectionMatrix * m_Camera.worldToCameraMatrix; //叠加变换用矩阵左乘: World -> View -> Projection
        m_ClipToWorldMatrix = VPMatrix.inverse; //这边相机自身是不发生变换的
    }

    private void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        m_FogMat.SetMatrix("_ClipToWorldMatrix", m_ClipToWorldMatrix);
        m_FogMat.SetFloat("_FogStrength", m_FogStrength);
        m_FogMat.SetColor("_FogColor", m_FogColor);
        m_FogMat.SetFloat("_FogStart", m_FogStart);
        m_FogMat.SetFloat("_FogHeight", m_FogHeight);

        Graphics.Blit(src, dest, m_FogMat);
    }

}

用到的shader

Shader "My/DepthTex/HeightFog"
{
    Properties
    {
    _MainTex("Texture", 2D) = "white" {}
    }

    SubShader
    {
        ZTest Always
        ZWrite Off

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;
                float2 uv_depth : TEXCOORD1;
            };

            sampler2D _CameraDepthTexture; //深度图
            sampler2D _MainTex; //后处理提供的屏幕图
            float4 _MainTex_TexelSize;
            float4x4 _ClipToWorldMatrix; //裁剪空间到世界空间转换矩阵, 需要c#部分提供

            float _FogStrength; //雾强度
            float4 _FogColor; //雾颜色
            float _FogStart; //雾开始高度
            float _FogHeight; //雾最大高度

            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);

                o.uv = v.uv;

                o.uv_depth = v.uv;
#if UNITY_UV_STARTS_AT_TOP
                if (_MainTex_TexelSize.y < 0) o.uv_depth.y = 1 - o.uv_depth.y;
#endif

                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth);
#if defined(UNITY_REVERSED_Z)
                depth = 1 - depth;
#endif
                float4 ndcPos = float4(i.uv.x * 2 - 1, i.uv.y * 2 - 1, depth * 2 - 1, 1); //后处理的那张贴图就对应整个屏幕, 所以可以直接用像素创建ndc坐标
                float4 worldPos = mul(_ClipToWorldMatrix, ndcPos); //ndcPos和clipPos只是差一个倍数(就是w分量)
                worldPos /= worldPos.w;

                //用世界坐标做相关处理
                float fogWeight = (_FogStart + _FogHeight - worldPos.y) / _FogHeight; //越高雾浓度越低
                fogWeight = saturate(fogWeight * _FogStrength); //限定在[0, 1]

                fixed4 c = tex2D(_MainTex, i.uv);
                c.rgb = lerp(c.rgb, _FogColor.rgb, fogWeight);
                return c;
            }
            ENDCG
        }
    }

    FallBack Off
}

 

参考

UnityShader基础(八)——深度纹理与法线纹理_unity 深度纹理_implosion98的博客-CSDN博客

《Shader入门精要》13.2,13.3

 

posted @ 2023-03-24 00:08  yanghui01  阅读(49)  评论(0编辑  收藏  举报