Planer Reflection

源代码来自Unity

https://github.com/keijiro/AdamPlaneReflection

参考:

Forward Mapped Planar Mirror Reflections

http://ws.iat.sfu.ca/papers/TR98-026.pdf

Planer Reflection_第1张图片

cs代码:

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

[ExecuteInEditMode]
public class PlaneReflection : MonoBehaviour {
    //分辨率
    public enum Dimension {
        x128    = 128,
        x256    = 256,
        x512    = 512,
        x1024   = 1024,
        x2048   = 2048,
        x4096   = 4096,
    }
    //生成反射贴图的shader
    [HideInInspector] public Shader convolveShader;

    public Dimension    reflectionMapSize = Dimension.x1024;
    //反射相机绘制的层
    public LayerMask    reflectLayerMask = ~0;
    //偏移
    public float        clipPlaneOffset = 0.01f;
    //是否剔除天空盒
    public bool         clipSkyDome;
    //反射相机nearPlane farPlane
    public float        nearPlaneDistance = 0.1f;
    public float        farPlaneDistance = 25f;
    //mip级数偏移
    public float        mipShift;
    //是否生成Depth Tex
    public bool         useDepth = true;
    public float        depthScale = 1.25f;
    public float        depthExponent = 2.25f;
    public float        depthRayPinchFadeSteps = 4f;
    //反射相机是否画阴影
    public bool         renderShadows = false;
    public float        shadowDistance = 200f;
    public int          maxPixelLights = -1;
    //clear color
    public Color        clearColor = Color.gray;
    public RenderingPath renderingPath = RenderingPath.UsePlayerSettings;

    RenderTexture               m_reflectionMap;
    RenderTexture               m_reflectionDepthMap;
    //???
    CommandBuffer m_copyDepthCB;
    //反射相机
    Camera                      m_reflectionCamera;
    Camera                      m_renderCamera;

    Material[]                  m_materials = new Material[0];

    Material                    m_convolveMaterial;

#if UNITY_EDITOR
    //编译器中,如果有改动重新编译该类就执行
    void OnValidate() {
        OnEnable();
        UnityEditor.SceneView.RepaintAll();
    }
#endif
    /// 
    /// 是否支持该shader
    /// 
    /// 
    bool CheckSupport() {
        bool supported = true;

        if(convolveShader && !convolveShader.isSupported)
            supported = false;

        return supported;
    }

    void Awake() {
        //初始化
        if(!convolveShader)
            convolveShader = Shader.Find("Hidden/Volund/Convolve");

        if(!m_convolveMaterial)
            m_convolveMaterial = new Material(convolveShader);
        
        if(CheckSupport()) {
            //初始化反射相机
            EnsureReflectionCamera(null);
            //初始化反射贴图
            EnsureReflectionTexture();
            //绘制Depth tex,不需要depth可以不走,多一次blit
            EnsureResolveDepthHooks();
        }
    }

    void OnEnable() {
        m_materials = GetComponent().sharedMaterials;

        if(!m_convolveMaterial)
            m_convolveMaterial = new Material(convolveShader);

        if(useDepth) {
            m_convolveMaterial.EnableKeyword("USE_DEPTH");
            m_convolveMaterial.SetFloat("_DepthScale", depthScale);
            m_convolveMaterial.SetFloat("_DepthExponent", depthExponent);

        } else {
            m_convolveMaterial.DisableKeyword("USE_DEPTH");
        }

        m_convolveMaterial.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;

        if(CheckSupport())
            EnsureReflectionCamera(null);
    }

    void OnDisable() {
        for(int i = 0, n = m_materials.Length; i < n; ++i)
            m_materials[i].DisableKeyword("PLANE_REFLECTION");
    }

    void OnDestroy() {
        if(m_reflectionCamera)
            Object.DestroyImmediate(m_reflectionCamera.gameObject);
        m_reflectionCamera = null;
        if(m_copyDepthCB != null) {
            m_copyDepthCB.Release();
            m_copyDepthCB = null;
        }
        Object.DestroyImmediate(m_convolveMaterial);
        m_convolveMaterial = null;
        Object.DestroyImmediate(m_reflectionMap);
        Object.DestroyImmediate(m_reflectionDepthMap);
    }
    //反射相机渲染之前
    public void OnWillRenderObject() {
        if(!CheckSupport())
            return;

        //Debug.LogFormat("OnWillRenderObject: {0} from camera {1} (DepthMode: {2})", name, Camera.current.name, Camera.current.depthTextureMode);

        if(Camera.current == Camera.main) {
            m_renderCamera = Camera.current;
#if UNITY_EDITOR
        } else if(UnityEditor.SceneView.currentDrawingSceneView && UnityEditor.SceneView.currentDrawingSceneView.camera == Camera.current) {
            m_renderCamera = Camera.current;
#endif
        } else {
            return;
        }
        //初始化相机
        m_reflectionCamera = EnsureReflectionCamera(m_renderCamera);
        //初始化反射贴图
        EnsureReflectionTexture();
         //绘制Depth tex,不需要depth可以不走,多一次blit
        EnsureResolveDepthHooks();

        var reflectionMap0 = m_reflectionMap;

        // find the reflection plane: position and normal in world space
        Vector3 pos = transform.position;
        //反射平面的法线方向
        Vector3 normal = transform.up;

        // Reflect camera around reflection plane
        //距离
        float d = -Vector3.Dot (normal, pos) - clipPlaneOffset;
        //反射面
        Vector4 reflectionPlane = new Vector4 (normal.x, normal.y, normal.z, d);
        //反射矩阵
        Matrix4x4 reflectionMatrix = Matrix4x4.zero;
        //计算反射矩阵
        CalculateReflectionMatrix(ref reflectionMatrix, reflectionPlane);
        //计算反射相机的位置
        Vector3 newpos = reflectionMatrix.MultiplyPoint(m_renderCamera.transform.position);
        //世界->相机->反射空间
        //反射相机绘制的物体也做反射的旋转&位移变换
        m_reflectionCamera.worldToCameraMatrix = m_renderCamera.worldToCameraMatrix * reflectionMatrix;
        //设置cull mask
        m_reflectionCamera.cullingMask = reflectLayerMask;
        //设置camera target为反射贴图
        m_reflectionCamera.targetTexture = reflectionMap0;
        m_reflectionCamera.transform.position = newpos;
        m_reflectionCamera.aspect = m_renderCamera.aspect;

        // find the reflection plane: position and normal in world space
        Vector3 planePos = transform.position;
        Vector3 planeNormal = transform.up;
        //?为什么又算一遍
        float planeDist = -Vector3.Dot(planeNormal, planePos) - clipPlaneOffset;
        /*var*/ reflectionPlane = new Vector4(planeNormal.x, planeNormal.y, planeNormal.z, planeDist);

        // reflect the camera about the reflection plane
        var srcCamPos = m_renderCamera.transform.position;
        //var srcCamPos4 = new Vector4(srcCamPos.x, srcCamPos.y, srcCamPos.z, 1f);
        var srcCamRgt = m_renderCamera.transform.right;
        var srcCamUp = m_renderCamera.transform.up;
        var srcCamFwd = m_renderCamera.transform.forward;
        //var reflectedPos = srcCamPos - 2f * Vector4.Dot(reflectionPlane, srcCamPos4) * planeNormal;
        //计算反射方向
        var reflectedDir = -ReflectVector(planeNormal, srcCamFwd);
        //反射相机看向反射方向
        m_reflectionCamera.transform.rotation = Quaternion.LookRotation(reflectedDir, srcCamUp);

        //只有第一帧会走,画Gizmos用
        if(m_reflectionCamera && ssnap) {
            sup = m_reflectionCamera.transform.up;
            spos = m_reflectionCamera.transform.position;
            srot = m_reflectionCamera.transform.rotation;
            sfov = m_reflectionCamera.fieldOfView;
            sfar = m_reflectionCamera.farClipPlane;
            snear = m_reflectionCamera.nearClipPlane;
            saspect = m_reflectionCamera.aspect;
            ssnap = false;
        }

        // Setup user defined clip plane instead of oblique frustum
        Shader.SetGlobalVector("_PlaneReflectionClipPlane", reflectionPlane);
        Shader.EnableKeyword("PLANE_REFLECTION_USER_CLIPPLANE");

        var oldShadowDist = QualitySettings.shadowDistance;
        if(!renderShadows)
            QualitySettings.shadowDistance = 0f;
        else if(shadowDistance > 0f)
            QualitySettings.shadowDistance = shadowDistance;

        var oldPixelLights = QualitySettings.pixelLightCount;
        if(maxPixelLights != -1)
            QualitySettings.pixelLightCount = maxPixelLights;
        //反射平面开启shader宏
        for(int i = 0, n = m_materials.Length; i < n; ++i)
            m_materials[i].DisableKeyword("PLANE_REFLECTION");

        GL.invertCulling = true;
        //提前渲染反射相机,渲出反射贴图
        m_reflectionCamera.Render();
        GL.invertCulling = false;

        for(int i = 0, n = m_materials.Length; i < n; ++i)
            m_materials[i].EnableKeyword("PLANE_REFLECTION");

        if(!renderShadows || shadowDistance > 0f)
            QualitySettings.shadowDistance = oldShadowDist;
        if(maxPixelLights != -1)
            QualitySettings.pixelLightCount = oldPixelLights;

        Shader.DisableKeyword("PLANE_REFLECTION_USER_CLIPPLANE");

        SetupConvolveParams(srcCamPos, srcCamRgt, srcCamUp, srcCamFwd, reflectionMatrix, planeNormal);
        //计算mipmap
        Convolve(m_reflectionCamera.targetTexture, m_reflectionDepthMap);
        m_reflectionCamera.targetTexture = null;

        float mipCount = Mathf.Max(0f, Mathf.Round(Mathf.Log ((float)m_reflectionMap.width, 2f)) - mipShift);
        for(int i = 0, n = m_materials.Length; i < n; ++i) {
            var m = m_materials[i];
            m.SetFloat("_PlaneReflectionLodSteps", mipCount);
            m.SetTexture("_PlaneReflection", m_reflectionMap);
        }
    }

    void EnsureReflectionTexture() {
        //如果反射贴图分辨率改变了||没有反射贴图,需要创建新的反射贴图
        var expectedSize = (int)reflectionMapSize;
        if(m_reflectionMap == null || m_reflectionMap.width != expectedSize || ((m_reflectionMap.depth == 0) == (m_reflectionCamera.actualRenderingPath == RenderingPath.Forward))) {
            Object.DestroyImmediate(m_reflectionMap);
            Object.DestroyImmediate(m_reflectionDepthMap);
            m_reflectionMap = new RenderTexture(expectedSize, expectedSize, 16, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
            m_reflectionMap.name = "PlaneReflection Full Color";
            m_reflectionMap.useMipMap = true;
            m_reflectionMap.autoGenerateMips = false;
            //因为有mipmap所以Trilinear,不用mipmap可以bilinear
            m_reflectionMap.filterMode = FilterMode.Trilinear;
            m_reflectionMap.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
            m_reflectionDepthMap = new RenderTexture(expectedSize, expectedSize, 0, RenderTextureFormat.RHalf, RenderTextureReadWrite.Linear);
            m_reflectionDepthMap.name = "PlaneReflection Full Depth";
            m_reflectionDepthMap.useMipMap = false;
            m_reflectionDepthMap.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
        }
    }

    void EnsureResolveDepthHooks() {
        if(m_copyDepthCB == null) {
            m_copyDepthCB = new CommandBuffer();
            m_copyDepthCB.name = "CopyResolveReflectionDepth";
            //走pass2画一张depth texture
            m_copyDepthCB.Blit(
                new RenderTargetIdentifier(BuiltinRenderTextureType.None),
                new RenderTargetIdentifier(m_reflectionDepthMap),
                m_convolveMaterial,
                2
            );
        }

        if(m_reflectionCamera.commandBufferCount == 0)
            m_reflectionCamera.AddCommandBuffer(CameraEvent.AfterEverything, m_copyDepthCB);
    }
    void SetupConvolveParams(Vector3 camPos, Vector3 camRgt, Vector3 camUp, Vector3 camFwd, Matrix4x4 reflectionMatrix, Vector3 planeNormal) {
        camPos = reflectionMatrix.MultiplyPoint(camPos);
        camRgt = -ReflectVector(camRgt, planeNormal);
        camUp = -ReflectVector(camUp, planeNormal);
        camFwd = -ReflectVector(camFwd, planeNormal);

        var camNear = m_reflectionCamera.nearClipPlane;
        var camFar = m_reflectionCamera.farClipPlane;
        var camFov = m_reflectionCamera.fieldOfView;
        var camAspect = m_reflectionCamera.aspect;

        var frustumCorners = Matrix4x4.identity;

        var fovWHalf = camFov * 0.5f;
        var tanFov = Mathf.Tan(fovWHalf * Mathf.Deg2Rad);

        var toRight = camRgt * camNear * tanFov * camAspect;
        var toTop = camUp * camNear * tanFov;

        var topLeft = (camFwd * camNear - toRight + toTop);
        var camScale = topLeft.magnitude * camFar / camNear;

        topLeft.Normalize();
        topLeft *= camScale;

        Vector3 topRight = camFwd * camNear + toRight + toTop;
        topRight.Normalize();
        topRight *= camScale;

        Vector3 bottomRight = camFwd * camNear + toRight - toTop;
        bottomRight.Normalize();
        bottomRight *= camScale;

        Vector3 bottomLeft = camFwd * camNear - toRight - toTop;
        bottomLeft.Normalize();
        bottomLeft *= camScale;

        frustumCorners.SetRow(0, topLeft);
        frustumCorners.SetRow(1, topRight);
        frustumCorners.SetRow(2, bottomRight);
        frustumCorners.SetRow(3, bottomLeft);

        Vector4 camPos4 = new Vector4(camPos.x, camPos.y, camPos.z, 1f);
        m_convolveMaterial.SetMatrix("_FrustumCornersWS", frustumCorners);
        m_convolveMaterial.SetVector("_CameraWS", camPos4);
        var zparams = Vector4.zero;
        zparams.y = farPlaneDistance / nearPlaneDistance;
        zparams.x = 1f - zparams.y;
        zparams.z = zparams.x / farPlaneDistance;
        zparams.z = zparams.y / farPlaneDistance;
#if UNITY_5_5_OR_NEWER
//requires version>5.5b10:
        if(SystemInfo.usesReversedZBuffer)
        {
            zparams.y += zparams.x;
            zparams.x = -zparams.x;
            zparams.w += zparams.z;
            zparams.z = -zparams.z;
        }
#endif
        m_convolveMaterial.SetVector("_PlaneReflectionZParams", zparams);
    }

    void Convolve(RenderTexture reflectionMap0, RenderTexture reflectionDepth) {
        // The simplest and most naive texture convolve the world ever saw. It sorta
        // gets the job done, though.

        var oldRT = RenderTexture.active;

        m_convolveMaterial.SetTexture("_CameraDepthTextureCopy", reflectionDepth);
        //生成mipmap
        for(int i = 0, n = m_reflectionMap.width; (n >> i) > 1; ++i)
            ConvolveStep(i, m_reflectionMap, i, i+1);

        RenderTexture.active = oldRT;
    }

    void ConvolveStep(int step, RenderTexture srcMap, int srcMip, int dstMip) {
        var srcSize = m_reflectionMap.width >> srcMip;
        var tmp = RenderTexture.GetTemporary(srcSize, srcSize, 0, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear);
        tmp.name = "PlaneReflection Half";

        var power = 2048 >> dstMip;
        m_convolveMaterial.SetFloat("_CosPower", (float)power / 1000f);
        m_convolveMaterial.SetFloat("_SampleMip", (float)srcMip);
        m_convolveMaterial.SetFloat("_RayPinchInfluence", Mathf.Clamp01((float)step / depthRayPinchFadeSteps));
        Graphics.SetRenderTarget(tmp, 0);
        CustomGraphicsBlit(srcMap, m_convolveMaterial, 0);

        m_convolveMaterial.SetFloat("_SampleMip", 0f);
        Graphics.SetRenderTarget(m_reflectionMap, dstMip);
        CustomGraphicsBlit(tmp, m_convolveMaterial, 1);

        RenderTexture.ReleaseTemporary(tmp);
    }

    static void CustomGraphicsBlit(RenderTexture src, Material mat, int pass) {
        mat.SetTexture("_MainTex", src);

        GL.PushMatrix();
        GL.LoadOrtho();

        mat.SetPass(pass);

        GL.Begin(GL.QUADS);

        GL.MultiTexCoord2(0, 0.0f, 0.0f);
        GL.Vertex3(0.0f, 0.0f, 3.0f); // BL

        GL.MultiTexCoord2(0, 1.0f, 0.0f);
        GL.Vertex3(1.0f, 0.0f, 2.0f); // BR

        GL.MultiTexCoord2(0, 1.0f, 1.0f);
        GL.Vertex3(1.0f, 1.0f, 1.0f); // TR

        GL.MultiTexCoord2(0, 0.0f, 1.0f);
        GL.Vertex3(0.0f, 1.0f, 0.0f); // TL

        GL.End();
        GL.PopMatrix();
    }

    void OnRenderObject() {
        if(!CheckSupport())
            return;

        //Debug.LogFormat("OnRenderObject: {0} from camera {1} (self rendercam: {2})", name, Camera.current.name, m_renderCamera);

        if(Camera.current != m_renderCamera) {
        } else {
            m_renderCamera = null;
        }
    }
    /// 
    /// 初始化反射相机
    /// 
    Camera EnsureReflectionCamera(Camera renderCamera) {
        if(!m_reflectionCamera) {
            //没有相机就生成相机
            var goCam = new GameObject(string.Format("#> _Planar Reflection Camera < ({0})", name));
            goCam.hideFlags = HideFlags.DontSave | HideFlags.NotEditable | HideFlags.HideInHierarchy;

            m_reflectionCamera = goCam.AddComponent();
            m_reflectionCamera.enabled = false;
        }
        
        if(renderCamera) {
            //copy当前渲染相机参数到反射相机
            m_reflectionCamera.CopyFrom(renderCamera);
            //重设一些参数
            // Undo some thing we don't want copied.
            m_reflectionCamera.ResetProjectionMatrix(); // definitely don't want to inherit an explicit projection matrix
            m_reflectionCamera.renderingPath = renderingPath == RenderingPath.UsePlayerSettings ? m_renderCamera.actualRenderingPath : renderingPath;
            m_reflectionCamera.allowHDR = renderCamera.allowHDR;
            m_reflectionCamera.rect = new Rect(0f, 0f, 1f, 1f);
        } else {
            m_reflectionCamera.renderingPath = renderingPath;
        }
        //设置参数
        m_reflectionCamera.backgroundColor = clearColor;
        m_reflectionCamera.clearFlags = CameraClearFlags.SolidColor;
        m_reflectionCamera.depthTextureMode = useDepth ? DepthTextureMode.Depth : DepthTextureMode.None;
        m_reflectionCamera.useOcclusionCulling = false;
        m_reflectionCamera.nearClipPlane = nearPlaneDistance;
        m_reflectionCamera.farClipPlane = farPlaneDistance + nearPlaneDistance;

        return m_reflectionCamera;
    }

    static Vector3 ReflectVector(Vector3 vec, Vector3 normal) {
        return 2f * Vector3.Dot(normal, vec) * normal - vec;
    }

    static void CalculateReflectionMatrix(ref Matrix4x4 reflectionMat, Vector4 plane) {
        reflectionMat.m00 = (1F - 2F*plane[0]*plane[0]);
        reflectionMat.m01 = (   - 2F*plane[0]*plane[1]);
        reflectionMat.m02 = (   - 2F*plane[0]*plane[2]);
        reflectionMat.m03 = (   - 2F*plane[3]*plane[0]);

        reflectionMat.m10 = (   - 2F*plane[1]*plane[0]);
        reflectionMat.m11 = (1F - 2F*plane[1]*plane[1]);
        reflectionMat.m12 = (   - 2F*plane[1]*plane[2]);
        reflectionMat.m13 = (   - 2F*plane[3]*plane[1]);

        reflectionMat.m20 = (   - 2F*plane[2]*plane[0]);
        reflectionMat.m21 = (   - 2F*plane[2]*plane[1]);
        reflectionMat.m22 = (1F - 2F*plane[2]*plane[2]);
        reflectionMat.m23 = (   - 2F*plane[3]*plane[2]);

        reflectionMat.m30 = 0F;
        reflectionMat.m31 = 0F;
        reflectionMat.m32 = 0F;
        reflectionMat.m33 = 1F;
    }


    public bool ssnap;
    Vector3 spos, sup; Quaternion srot;
    float sfov, snear, sfar, saspect;
    void OnDrawGizmos() {
        Gizmos.color = Color.red;
        var s = transform.rotation * new Vector3(0.15f, 0.05f, 0.1f);
        s.Set(Mathf.Abs(s.x), Mathf.Abs(s.y), s.z = Mathf.Abs(s.z));
        Gizmos.DrawCube(transform.position, s);
        Gizmos.DrawSphere(transform.position + transform.up * 0.025f, 0.05f);

        if(sfov != 0f && snear != 0f && sfar != 0f) {
            Gizmos.DrawLine(spos, spos + sup * 0.5f);
            Gizmos.matrix = Matrix4x4.TRS(spos, srot, Vector3.one);
            Gizmos.DrawFrustum(Vector3.zero, sfov, sfar, snear, saspect);
        }
    }
}

计算mipmap部分shader:

Shader "Hidden/Volund/Convolve" {
Properties {
	_MainTex("Diffuse", 2D) = "white" {}
	_DepthScale("DepthScale", Float) = 1.0
	_DepthExponent("DepthExponent", Float) = 1.0
}

CGINCLUDE

#pragma only_renderers d3d11
#pragma target 3.0

#include "UnityCG.cginc"

uniform sampler2D _MainTex;
uniform float4 _MainTex_TexelSize;

uniform sampler2D _CameraDepthTexture;
uniform sampler2D _CameraDepthTextureCopy;

uniform float4x4	_FrustumCornersWS;
uniform float4		_CameraWS;

uniform float		_DepthScale;
uniform float		_DepthExponent;
uniform float		_SampleMip;
uniform float		_CosPower;
uniform float		_RayPinchInfluence;

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

v2f vert(appdata_img v)  {
	v2f o;
	half index = v.vertex.z;
	v.vertex.z = 0.1;
	o.pos = UnityObjectToClipPos(v.vertex);
	o.uv = v.texcoord;
	o.interpolatedRay = _FrustumCornersWS[(int)index];
	o.interpolatedRay.w = index;
	o.interpolatedRayN = normalize(o.interpolatedRay.xyz);
	return o;
}

uniform float4 _PlaneReflectionClipPlane;
uniform float4 _PlaneReflectionZParams;


float4 frag(v2f i, const float2 dir) {
	float4 baseUV;
	baseUV.xy = i.uv.xy;
	baseUV.z = 0;
	baseUV.w = _SampleMip;
	
#if USE_DEPTH
//	float rawDepth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
//	float depth = 1.f / (rawDepth * _PlaneReflectionZParams.x + _PlaneReflectionZParams.y);
	float depth = tex2D(_CameraDepthTextureCopy, i.uv);

	float3 wsDir = depth * i.interpolatedRay.xyz;
	float4 wsPos = float4(_CameraWS.xyz + wsDir, 1.f);
	float pointToPlaneDist = dot(wsPos, _PlaneReflectionClipPlane) / dot(_PlaneReflectionClipPlane.xyz, normalize(i.interpolatedRayN));
	float sampleScale1 = saturate(pow(saturate(pointToPlaneDist * _DepthScale), _DepthExponent));
	sampleScale1 = max(_RayPinchInfluence, sampleScale1);
#else
	float sampleScale1 = 1.f;
#endif
	float2 sampleScale = dir * _MainTex_TexelSize.xy * sampleScale1;

	float weight = 0.f;
	float4 color = 0.f;

	float4 uv = baseUV;

	for(int i = -32; i <= 32; i += 2) {
		float2 off = i * sampleScale;
		uv.xy = baseUV.xy + off;

		// Kill any samples falling outside of the screen.
		// Otherwise, as a bright source pixel touches the edge of the screen, it suddenly
		// gets exploded by clamping to have the width/height equal to kernel's radius
		// and introduces that much more energy to the result.
		if (any(uv.xy < 0.0) || any(uv.xy > 1.0))
			continue;
		
		float4 s = tex2Dlod(_MainTex, uv);

		float c = clamp(i / 20.f, -1.57f, 1.57f);
		float w = pow(max(0.f, cos(c)), _CosPower);
	
		color.rgb += s.rgb * w;
		weight += w;
	}

		return color.rgbb / weight;
}

float4 fragH(v2f i) : COLOR { return frag(i, float2(1.f, 0.f)); }
float4 fragV(v2f i) : COLOR { return frag(i, float2(0.f, 1.f)); }


float fragResolve(v2f i) : SV_Target{
	float rawDepth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);
	float depth = 1.f / (rawDepth * _PlaneReflectionZParams.x + _PlaneReflectionZParams.y);
	return depth;
}

ENDCG

SubShader {
	Cull Off ZTest Always ZWrite Off

	Pass {
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment fragH
		#pragma multi_compile _ USE_DEPTH
		#pragma multi_compile _ CP0 CP1 CP2 CP3
		ENDCG
	}
	
	Pass {
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment fragV
		#pragma multi_compile _ USE_DEPTH
		#pragma multi_compile _ CP0 CP1 CP2 CP3
		ENDCG
	}

	Pass {
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment fragResolve
		ENDCG
	}
}
}

材质shader,读取反射贴图部分:

				float mip = pow(1.f - s.oneMinusRoughness, 3.0 / 4.0) * _PlaneReflectionLodSteps;
				//裁剪空间位置/屏幕宽高
				float2 vpos = i.pos / _ScreenParams.xy;

			#ifdef _NORMALMAP
				half3 tanNormal = NormalInTangentSpace(i.tex);
				vpos.xy += clamp(tanNormal.xy * _PlaneReflectionBumpScale /* * float2(-1.f, -1.f)*/, -_PlaneReflectionBumpClamp, _PlaneReflectionBumpClamp);
			#endif
				float4 lookup = float4(vpos.x, vpos.y, 0.f, mip);
				float4 hdrRefl = tex2Dlod(_PlaneReflection, lookup);
				gi.indirect.specular = hdrRefl.rgb * _PlaneReflectionIntensityScale * occlusion;

------Add wolf96 2019/4/1

解决水面下反射问题

利用倾斜裁剪


        Vector4 clipPlane = reflectionPlane;
        //切换到反射相机空间
        clipPlane = m_reflectionCamera.worldToCameraMatrix.inverse.transpose * clipPlane;
        Matrix4x4 projectMatrix = m_reflectionCamera.projectionMatrix;
        Vector4 q;
        q.x = (Mathf.Sign(clipPlane.x) + projectMatrix.m02) / projectMatrix.m00;
        q.y = (Mathf.Sign(clipPlane.y) + projectMatrix.m12) / projectMatrix.m11;
        q.z = -1;
        q.w = (1 + projectMatrix.m22) / projectMatrix.m23;
        Vector4 c = clipPlane * (2 / Vector4.Dot(clipPlane, q));
        projectMatrix.m20 = c.x;
        projectMatrix.m21 = c.y;
        projectMatrix.m22 = c.z + 1;
        projectMatrix.m23 = c.w;
        m_reflectionCamera.projectionMatrix = projectMatrix;
        GL.invertCulling = true;
        m_reflectionCamera.Render();
        GL.invertCulling = false;

参考:3D游戏与计算机图形学中的数学方法 5.6镜像与倾斜裁剪

------Add wolf96 2019/4/25
用斜切裁剪导致farplane也变斜,导致远处剔除的距离变远,画的更多了,可以设置Camera cullingDistance
反射相机的Camera Target和屏幕比例一样比较好,水面上面其实没有画东西

 

你可能感兴趣的:(Shader)