Unity Shader学习(六)---详谈深度纹理和法线纹理

深度纹理和法线纹理上进行采样等操作,会使物体不受外部光照因素影响,保存的是当前渲染物体的真实信息,类似于边缘检测等会更可靠。

深度纹理:就是一张渲染纹理,只不过它里面存储的像素值不是颜色值,而是一个高精度的深度值。这些深度值来自于顶点变换后得到的归一化的设备坐标(NDC)。变换到NDC时,z坐标是从-1 , 1之间。为了可以存储在一张图中,我们将其转换:d = 0.5 *Zndc + 0.5。d对应了深度纹理中的像素值。

在Unity中,如果使用延迟渲染,自然会把深度纹理存储在G缓冲区中。如果没有使用延迟渲染,Unity中可以设置RenderType标签为Opaque的物体,判断它们使用的渲染队列是否小于2500,如果满足就渲染到深度和法线纹理中。

Unity获取深度纹理和法线纹理

camera.depthTextureMode = DepthTextureMode.Depth

camera.depthTextureMode = DepthTextureMode.DepthNormals

 将=换为|=即可获取两种纹理

float d = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture,i.uv) 

(一)全局雾效

Unity自带的雾效需要为场景中所有的物体添加,而且复杂的雾效,例如基于高度的雾效就是不可以的。
利用深度纹理重建每个像素在世界空间下的位置。
需要先计算出世界空间下摄像机的topRight topLeft bottomLeft bottomRight四个点的位置,然后shader中根据x y分量计算出属于哪个角,然后得到该顶点的interpolatedRay插值后的像素向量。
f = (Hend - y)/(Hend - Hstart) Hstart Hend 表示受雾影响的起始高度和中指高度。再与fogDensity雾的浓度相乘得到最后的雾效系数,与原始颜色进行混合得到最后的效果。
在程序中计算得到摄像机的topRight topLeft bottomLeft bottomRight四个点的位置,
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;
在shader中根据顶点x y 值的大小确定是哪一部分
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;
}
SAMPLE_DEPTH_TEXTURE对深度纹理进行采样(camera.depthTextureMode |= DepthTextureMode.Depth;程序中得到的),LinearEyeDepth得到视角空间下的线形深度值。

程序代码,主要是传入一些属性和计算裁剪平面的四个角对应的向量。

using UnityEngine;
using System.Collections;

public class FogWithDepthTexture : 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.0f, 3.0f)]
    public float fogDensity = 1.0f;

    public Color fogColor = Color.white;

    public float fogStart = 0.0f;
    public float fogEnd = 2.0f;

    void OnEnable() {
        camera.depthTextureMode |= DepthTextureMode.Depth;
    }
    
    void OnRenderImage (RenderTexture src, RenderTexture dest) {
        if (material != null) {
            Matrix4x4 frustumCorners = Matrix4x4.identity;

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

            material.SetFloat("_FogDensity", fogDensity);
            material.SetColor("_FogColor", fogColor);
            material.SetFloat("_FogStart", fogStart);
            material.SetFloat("_FogEnd", fogEnd);

            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 13/Fog With Depth Texture" {
    Properties {
        _MainTex ("Base (RGB)"2D) = "white" {}
        _FogDensity ("Fog Density"Float) = 1.0
        _FogColor ("Fog Color"Color) = (1111)
        _FogStart ("Fog Start"Float) = 0.0
        _FogEnd ("Fog End"Float) = 1.0
    }
    SubShader {
        CGINCLUDE
        
        #include "UnityCG.cginc"
        
        float4x4 _FrustumCornersRay;
        
        sampler2D _MainTex;
        half4 _MainTex_TexelSize;
        sampler2D _CameraDepthTexture;
        half _FogDensity;
        fixed4 _FogColor;
        float _FogStart;
        float _FogEnd;
        
        struct v2f {
            float4 pos : SV_POSITION;
            half2 uv : TEXCOORD0;
            half2 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;
                        
            float fogDensity = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart); 
            fogDensity = saturate(fogDensity * _FogDensity);
            
            fixed4 finalColor = tex2D(_MainTex, i.uv);
            finalColor.rgb = lerp(finalColor.rgb, _FogColor.rgb, fogDensity);
            
            return finalColor;
        }
        
        ENDCG
        
        Pass {
            ZTest Always Cull Off ZWrite Off
                     
            CGPROGRAM  
            
            #pragma vertex vert  
            #pragma fragment frag  
              
            ENDCG  
        }
    } 
    FallBack Off
}





你可能感兴趣的:(Unity,计算机图形学)