Shader 学习之路-镜像Shader 练习(八)

在游戏中,我们会经常看到一些物体镜像的效果,今天我们来学习如何实现一个镜像效果的Shader。

1、首先实现镜像的核心Shader,我们命名为MirrorsShader.shader 的顶点着色器。代码如下:

Shader "Custom/MirrorsShader" {

    Properties

    {

        _Color("Main Color", Color) = (1,1,1,1)

        _MainTex("Texture", 2D) = "white" {}

        _BumpMap("Normalmap", 2D) = "bump" {}

        _ReflAmount("Reflection amount", float) = 0.5

        _ReflDistort("Reflection distort", float) = 0.25

        [HideInInspector]_ReflectionTex("Reflection", 2D) = "white" { }

    }

        SubShader

        {

            Tags{ "RenderType" = "Opaque" }

            LOD 100

        Pass

            {

            CGPROGRAM

            #pragma vertex vert

            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata

            {

                float4 vertex : POSITION;

                float2 uv : TEXCOORD0;

                float2 uv1 : TEXCOORD1;

            };

            struct v2f

            {

                float2 uv : TEXCOORD0;

                float2 uv1 : TEXCOORD1;

                float4 vertex : SV_POSITION;

                float4 screenPos : TEXCOORD2;

            };

            sampler2D _MainTex;

            float4 _MainTex_ST;

            sampler2D _BumpMap;

            float4 _BumpMap_ST;

            sampler2D _ReflectionTex;

            float4 _Color;

            float _ReflAmount;

            float _ReflDistort;

            v2f vert(appdata v)

            {

                v2f o;

                o.vertex = UnityObjectToClipPos(v.vertex);

                o.screenPos = ComputeScreenPos(o.vertex);

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);

                o.uv1 = TRANSFORM_TEX(v.uv1, _BumpMap);

                return o;

            }

            #define FLT_MAX 3.402823466e+38

            #define FLT_MIN 1.175494351e-38

            #define DBL_MAX 1.7976931348623158e+308

            #define DBL_MIN 2.2250738585072014e-308

            fixed4 frag(v2f i) : COLOR

            {

                fixed4 tex = tex2D(_MainTex, i.uv);

                fixed3 nor = UnpackNormal(tex2D(_BumpMap, i.uv1));


                fixed2 screenUV = (i.screenPos.xy) / (i.screenPos.w+FLT_MIN);

                screenUV.xy += nor *_ReflDistort;

                fixed4 refl = tex2D(_ReflectionTex, screenUV);

                return (refl*_ReflAmount) + (tex*_Color*tex.a);

            }

            ENDCG

        }

    }

}

2、为了效果更好,我们准备Blur 效果的Shader,代码如下:

Shader "Custom/BlursLOD"

{

    Properties

    {

        _CustomFloatParam1("Iteration", float) = 1

        _CustomFloatParam2("Neighbour", float) = 1

        _MainTex("Base (RGB)", 2D) = "" {}

        _Lod("Lod",float) = 0

    }

    SubShader

    {

        Pass

        {

            ZTest Always 

            Cull Off

            Fog{ Mode 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;

            float4 _MainTex_ST;

            float _Lod;

            float _CustomFloatParam1;

            float _CustomFloatParam2;

            v2f vert(appdata v)

            {

                v2f o;

                o.vertex = UnityObjectToClipPos(v.vertex);

                o.uv = TRANSFORM_TEX(v.uv, _MainTex);

                return o;

            }

            #define FLT_MAX 3.402823466e+38

            #define FLT_MIN 1.175494351e-38

            #define DBL_MAX 1.7976931348623158e+308

            #define DBL_MIN 2.2250738585072014e-308

            fixed4 frag(v2f i) : COLOR

            {

                float stepX = (1.0 / (_ScreenParams.xy / _ScreenParams.w+FLT_MIN).x)*(_CustomFloatParam2 + (_CustomFloatParam1 % 2));

                float stepY = (1.0 / (_ScreenParams.xy / _ScreenParams.w+FLT_MIN).y)*(_CustomFloatParam2 + (_CustomFloatParam1 % 2));

                half4 color = float4 (0,0,0,0);

                fixed2 copyUV;

                copyUV.x = i.uv.x - stepX;

                copyUV.y = i.uv.y - stepY;

                color += tex2Dlod (_MainTex, float4(copyUV,0,_Lod))*0.077847;

                copyUV.x = i.uv.x;

                copyUV.y = i.uv.y - stepY;

                color += tex2Dlod (_MainTex, float4(copyUV,0,_Lod))*0.123317;

                copyUV.x = i.uv.x + stepX;

                copyUV.y = i.uv.y - stepY;

                color += tex2Dlod (_MainTex, float4(copyUV,0,_Lod))*0.077847;

                copyUV.x = i.uv.x - stepX;

                copyUV.y = i.uv.y;

                color += tex2Dlod (_MainTex, float4(copyUV,0,_Lod))*0.123317;

                copyUV.x = i.uv.x;

                copyUV.y = i.uv.y;

                color += tex2Dlod (_MainTex, float4(copyUV,0,_Lod))*0.195346;

                copyUV.x = i.uv.x + stepX;

                copyUV.y = i.uv.y;

                color += tex2Dlod (_MainTex, float4(copyUV,0,_Lod))*0.123317;

                copyUV.x = i.uv.x - stepX;

                copyUV.y = i.uv.y + stepY;

                color += tex2Dlod (_MainTex, float4(copyUV,0,_Lod))*0.077847;

                copyUV.x = i.uv.x;

                copyUV.y = i.uv.y + stepY;

                color += tex2Dlod (_MainTex, float4(copyUV,0,_Lod))*0.123317;

                copyUV.x = i.uv.x + stepX;

                copyUV.y = i.uv.y + stepY;

                color += tex2Dlod (_MainTex, float4(copyUV,0,_Lod))*0.077847;

        //        //5*5 gaus

        //        fixed2 copyUV;

        //

        //        copyUV.x = i.uv.x + stepX*-2;

        //        copyUV.y = i.uv.y + stepY*-2;

        //        color += tex2D (_MainTex, copyUV)*0.0036630036; // 1/273

        //        copyUV.x = i.uv.x - stepX; //*-1

        //        copyUV.y = i.uv.y + stepY*-2;

        //        color += tex2D (_MainTex, copyUV)*0.0146520146; // 4/273

        //        copyUV.x = i.uv.x; // + stepX*0;

        //        copyUV.y = i.uv.y + stepY*-2;

        //        color += tex2D (_MainTex, copyUV)*0.0256410256; // 7/273

        //        copyUV.x = i.uv.x + stepX; //*1

        //        copyUV.y = i.uv.y + stepY*-2;

        //        color += tex2D (_MainTex, copyUV)*0.0146520146; // 4/273

        //        copyUV.x = i.uv.x + stepX*2;

        //        copyUV.y = i.uv.y + stepY*-2;

        //        color += tex2D (_MainTex, copyUV)*0.0036630036; // 1/273

        //

        //        copyUV.x = i.uv.x + stepX*-2;

        //        copyUV.y = i.uv.y - stepY; //*-1;

        //        color += tex2D (_MainTex, copyUV)*0.0146520146; // 4/273

        //        copyUV.x = i.uv.x - stepX; //*-1;

        //        copyUV.y = i.uv.y - stepY; //*-1;

        //        color += tex2D (_MainTex, copyUV)*0.0586080586; // 16/273

        //        copyUV.x = i.uv.x; // + stepX*0;

        //        copyUV.y = i.uv.y - stepY; //*-1;

        //        color += tex2D (_MainTex, copyUV)*0.0952380952; // 26/273

        //        copyUV.x = i.uv.x + stepX; //*1;

        //        copyUV.y = i.uv.y - stepY; //*-1;

        //        color += tex2D (_MainTex, copyUV)*0.0586080586; // 16/273

        //        copyUV.x = i.uv.x + stepX*2;

        //        copyUV.y = i.uv.y - stepY; //*-1;

        //        color += tex2D (_MainTex, copyUV)*0.0146520146; // 4/273

        //

        //        copyUV.x = i.uv.x + stepX*-2;

        //        copyUV.y = i.uv.y; // + stepY*0;

        //        color += tex2D (_MainTex, copyUV)*0.0256410256; // 7/273

        //        copyUV.x = i.uv.x - stepX; //*-1;

        //        copyUV.y = i.uv.y; // + stepY*0;

        //        color += tex2D (_MainTex, copyUV)*0.0952380952; // 26/273

        //        copyUV.x = i.uv.x; // + stepX*0;

        //        copyUV.y = i.uv.y; // + stepY*0;

        //        color += tex2D (_MainTex, copyUV)*0.1501831501; // 41/273

        //        copyUV.x = i.uv.x + stepX; //*1;

        //        copyUV.y = i.uv.y; // + stepY*0;

        //        color += tex2D (_MainTex, copyUV)*0.0952380952; // 26/273

        //        copyUV.x = i.uv.x + stepX*2;

        //        copyUV.y = i.uv.y; // + stepY*0;

        //        color += tex2D (_MainTex, copyUV)*0.0256410256; // 7/273

        //

        //        copyUV.x = i.uv.x + stepX*-2;

        //        copyUV.y = i.uv.y + stepY;

        //        color += tex2D (_MainTex, copyUV)*0.0146520146; // 4/273

        //        copyUV.x = i.uv.x - stepX; //*-1;

        //        copyUV.y = i.uv.y + stepY;

        //        color += tex2D (_MainTex, copyUV)*0.0586080586; // 16/273

        //        copyUV.x = i.uv.x; // + stepX*0;

        //        copyUV.y = i.uv.y + stepY;

        //        color += tex2D (_MainTex, copyUV)*0.0952380952; // 26/273

        //        copyUV.x = i.uv.x + stepX; //*1;

        //        copyUV.y = i.uv.y + stepY;

        //        color += tex2D (_MainTex, copyUV)*0.0586080586; // 16/273

        //        copyUV.x = i.uv.x + stepX*2;

        //        copyUV.y = i.uv.y + stepY;

        //        color += tex2D (_MainTex, copyUV)*0.0146520146; // 4/273

        //

        //        copyUV.x = i.uv.x + stepX*-2;

        //        copyUV.y = i.uv.y + stepY*2;

        //        color += tex2D (_MainTex, copyUV)*0.0036630036; // 1/273

        //        copyUV.x = i.uv.x - stepX; //*-1;

        //        copyUV.y = i.uv.y + stepY*2;

        //        color += tex2D (_MainTex, copyUV)*0.0146520146; // 4/273

        //        copyUV.x = i.uv.x; // + stepX*0;

        //        copyUV.y = i.uv.y + stepY*2;

        //        color += tex2D (_MainTex, copyUV)*0.0256410256; // 7/273

        //        copyUV.x = i.uv.x + stepX; //*1;

        //        copyUV.y = i.uv.y + stepY*2;

        //        color += tex2D (_MainTex, copyUV)*0.0146520146; // 4/273

        //        copyUV.x = i.uv.x + stepX*2;

        //        copyUV.y = i.uv.y + stepY*2;

        //        color += tex2D (_MainTex, copyUV)*0.0036630036; // 1/273

                return color;

            }

            ENDCG

        }

    }

}

3、我们通过在Unity的检视面板中,MirrorsWithShader.cs 实现镜像的效果。

[ExecuteInEditMode]

public class MirrorsWithShader : EffectBase 

{

    public string UniqueName = "";

    public bool UpdateOnEditor = true;

    public WorkType WorkType = WorkType.Reflect;

    //public bool IsDirect = false;

    //public bool IsForTransparency = false;

    public bool UseCameraClipPlane = false;

    //public Vector3 Normal = Vector3.up;

    public FollowVector UpVector = FollowVector.GreenY;

    public bool DisablePixelLights = true;

    public int TextureSize = 256;

    public float ClipPlaneOffset = 0f;

    public Camera Camera;

    public LayerMask ReflectLayers = -1;

    public GameObject ReflectionCameraPrefab = null;

    private GameObject _reflectionCameraPrefabInstance = null;

    [Space(20)]

    [Header("\"Shader to run on texture\" settings")]

    public Shader Shader;

    public int Lod = 0;

    [Range(1, 20)]

    public int Iterations = 3;

    public float CustomFloatParam2 = 3;

    private Material _material;

    private Hashtable _reflectionCameras = new Hashtable(); // Camera -> Camera table

    private RenderTexture _reflectionTexture1;

    private RenderTexture _reflectionTexture2;

    private RenderTexture _reflectionTexture3;

    private int _oldReflectionTextureSize;

    public static Quaternion QuaternionFromMatrix(Matrix4x4 m) { return Quaternion.LookRotation(m.GetColumn(2), m.GetColumn(1)); }

    public static Vector4 PosToV4(Vector3 v) { return new Vector4(v.x, v.y, v.z, 1.0f); }

    public static Vector3 ToV3(Vector4 v) { return new Vector3(v.x, v.y, v.z); }

    public static Vector3 ZeroV3 = new Vector3(0.0f, 0.0f, 0.0f);

    public static Vector3 OneV3 = new Vector3(1.0f, 1.0f, 1.0f);

    void Start()

    {

        //do not render it again for same named scripts

        UniqueName = (string.IsNullOrEmpty(UniqueName) == true ? Guid.NewGuid().ToString() : UniqueName);

    }

    public void OnWillRenderObject()

    {

        if (!UpdateOnEditor)

        {

            //disable render on editor scene view! open game window always to see the effect on design!

            //Debug.Log(Camera.current.name);

            #if UNITY_EDITOR

            if (Camera.current.name == "SceneCamera")

            {

                return;

            }

            #endif

        }

        var rend = GetComponent<Renderer>();

        RenderMe(rend.sharedMaterials.Where(a => a != null).ToArray());

    }

    void RenderMe(Material[] materials)

    {

        // Safeguard from recursive draws       

        if (InsideRendering)

            return;

        InsideRendering = true;

        if (Camera == null && ReflectionCameraPrefab == null)

        {

            return; //!!

            //Camera = Camera.current; !!!do not use scene cam

        }

        var renderToTexture = true;

        if (_material)

        {

            DestroyImmediate(_material);

            _material = null;

        }

        if (Shader)

        {

            _material = new Material(Shader);

            _material.hideFlags = HideFlags.HideAndDontSave;

            if (_material.HasProperty("_CustomFloatParam2"))

            {

                _material.SetFloat("_CustomFloatParam2", CustomFloatParam2);

            }

            if (_material.HasProperty("_Lod"))

            {

                _material.SetFloat("_Lod", Lod);

            }

        }

        // Optionally disable pixel lights for reflection

        int oldPixelLightCount = QualitySettings.pixelLightCount;

        if (DisablePixelLights)

            QualitySettings.pixelLightCount = 0;

        //var mainCamOldPosition = m_Camera.transform.position;

        //var mainCamOldRotation = m_Camera.transform.rotation;

        //Camera cam = m_Camera;

        ////setup

        Camera reflectionCamera;

        CreateMirrorObjects(Camera, out reflectionCamera);

        UpdateCameraModes(Camera, reflectionCamera);

        reflectionCamera.cullingMask = ~(1 << 4) & ReflectLayers.value; // never render water layer

        reflectionCamera.targetTexture = _reflectionTexture1;

        //if (WorkType == WorkType.Direct || WorkType == WorkType.Reflect)

        //{

        try

        {

            AlreadyRendered.Remove(UniqueName + "_" + (Time.frameCount - 1));

            #if DEBUG_RENDER

            Debug.Log("Removed previous entry " + UniqueName + "_" + (Time.frameCount - 1));

            #endif

        }

        catch

        {

        }

        try

        {

            RenderTexture myOut;

            if (AlreadyRendered.TryGetValue(UniqueName + "_" + Time.frameCount, out myOut))

            {

                #if DEBUG_RENDER

                Debug.Log("Render already made for this frame skipping " + UniqueName + "_" + Time.frameCount);

                #endif

                _reflectionTexture1 = myOut;

                renderToTexture = false;

            }

        }

        catch

        {

        }

        //}

        Vector3 Normal;

        //if (WorkType == WorkType.Direct)

        //{

        //    Normal = Vector3.up;//use always up for isDirect mode

        //}

        //else 

        if (UpVector == FollowVector.GreenY)

        {

            Normal = gameObject.transform.up;

        }

        else if (UpVector == FollowVector.GreenY_Negative)

        {

            Normal = -gameObject.transform.up;

        }

        else if (UpVector == FollowVector.BlueZ)

        {

            Normal = gameObject.transform.forward;

        }

        else if (UpVector == FollowVector.BlueZ_Negative)

        {

            Normal = -gameObject.transform.forward;

        }

        else if (UpVector == FollowVector.RedX)

        {

            Normal = gameObject.transform.right;

        }

        else //if (UpVector == FollowVector.RedX_Negative)

        {

            Normal = -gameObject.transform.right;

        }

        //do not use clip plane on isdirect!!!

        //if (UseCameraClipPlane && IsDirect)

        //{

        //    Vector4 clipPlaneWorldSpace = new Vector4(Normal.x, Normal.y, Normal.z, 

        //        Vector3.Dot(transform.position, Normal)-ClipPlaneOffset);

        //    Vector4 clipPlaneCameraSpace = Matrix4x4.Transpose(Matrix4x4.Inverse(Camera.worldToCameraMatrix)) * clipPlaneWorldSpace;

        //    // Update projection based on new clip plane

        //    // Note: http://aras-p.info/texts/obliqueortho.html and http://www.terathon.com/lengyel/Lengyel-Oblique.pdf

        //    reflectionCamera.projectionMatrix = Camera.CalculateObliqueMatrix(clipPlaneCameraSpace);

        //}

        if (renderToTexture)

        {

            if (WorkType != WorkType.Direct && WorkType != WorkType.WaterBottom)

            {

                // find out the reflection plane: position and normal in world space

                Vector3 pos = transform.position;

                Vector3 normal = Normal;

                float d = -Vector3.Dot(normal, pos) - ClipPlaneOffset;

                Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d);

                // Render reflection

                // Reflect camera around reflection plane

                Matrix4x4 reflection = Matrix4x4.zero;

                CalculateReflectionMatrix(ref reflection, reflectionPlane);

                Vector3 oldpos = Camera.transform.position;

                Vector3 newpos = reflection.MultiplyPoint(oldpos);

                reflectionCamera.worldToCameraMatrix = Camera.worldToCameraMatrix * reflection;

                Vector4 clipPlane = CameraSpacePlane(reflectionCamera, pos, normal, 1.0f);

                //Matrix4x4 projection = cam.projectionMatrix;

                Matrix4x4 projection = Camera.CalculateObliqueMatrix(clipPlane);

                reflectionCamera.projectionMatrix = projection;

                GL.invertCulling = true;

                reflectionCamera.transform.position = newpos;

                Vector3 euler = Camera.transform.eulerAngles;

                reflectionCamera.transform.eulerAngles = new Vector3(0, euler.y, euler.z);

                #if DEBUG_RENDER

                Debug.Log("Rendering for mirror... frame: " + Time.frameCount);

                #endif

                reflectionCamera.Render();

                reflectionCamera.transform.position = oldpos;

                GL.invertCulling = false;

            }

            else

            {

                #if DEBUG_RENDER

                Debug.Log("Rendering for direct... " + UniqueName + "_" + Time.frameCount);

                #endif

                if (ReflectionCameraPrefab == null) //use main camera transform and position if prefab is null

                {

                    reflectionCamera.transform.position = Camera.transform.position;

                    reflectionCamera.transform.rotation = Camera.transform.rotation;

                }

                if (UseCameraClipPlane)

                {

                    // find out the reflection plane: position and normal in world space

                    Vector3 pos = transform.position;

                    Vector3 normal = Normal;

                    Vector4 clipPlane = CameraSpacePlane(reflectionCamera, pos, normal, -1.0f);

                    Matrix4x4 projection = Camera.CalculateObliqueMatrix(clipPlane);

                    reflectionCamera.projectionMatrix = projection;

                }

                reflectionCamera.Render();

            }

        }

        if (Lod > 0)

        {

            _reflectionTexture1.GenerateMips();

        }

        //hold texture1 unchanged!!

        Graphics.Blit(_reflectionTexture1, _reflectionTexture2);

        if (Lod > 0)

        {

            _reflectionTexture2.GenerateMips();

        }

        if (Shader != null && _material != null)

        {

            for (int i = 1; i <= Iterations; i++)

            {

                if (_material.HasProperty("_CustomFloatParam1"))

                    _material.SetFloat("_CustomFloatParam1", i);

                if (i % 2 == 1) //a little hack to copy textures in order from 1 to 2 than 2 to 1 and so :)

                {

                    Graphics.Blit(_reflectionTexture2, _reflectionTexture3, _material);

                    if (Lod > 0)

                    {

                        _reflectionTexture3.GenerateMips();

                    }

                }

                else

                {

                    Graphics.Blit(_reflectionTexture3, _reflectionTexture2, _material);

                    if (Lod > 0)

                    {

                        _reflectionTexture2.GenerateMips();

                    }

                }

            }

        }

        foreach (Material mat in materials)

        {

            if (WorkType == WorkType.Direct || 

                WorkType == WorkType.Reflect ||

                WorkType == WorkType.Transparent)

                SetMaterial(mat, "_ReflectionTex");

            if (WorkType == WorkType.WaterTop)

                SetMaterial(mat, "_ReflectionTex");

            if (WorkType == WorkType.WaterBottom)

                SetMaterial(mat, "_ReflectionTex2");

            if (mat.HasProperty("_IsReverse"))

            {

                mat.SetFloat("_IsReverse", WorkType == WorkType.Direct ? 1 : 0);

            }

        }

        // Restore pixel light count

        if (DisablePixelLights)

            QualitySettings.pixelLightCount = oldPixelLightCount;

        //if (WorkType == WorkType.Direct || WorkType == WorkType.Reflect)

        //{

        try

        {

            RenderTexture myOut;

            if (!AlreadyRendered.TryGetValue(UniqueName + "_" + Time.frameCount, out myOut))

            {

                AlreadyRendered.Add(UniqueName + "_" + Time.frameCount, _reflectionTexture1);

                #if DEBUG_RENDER

                Debug.Log("Added to renderlist: " + UniqueName + "_" + Time.frameCount);

                #endif

            }

            myOut = null;

        }

        catch

        {

        }

        //}

        InsideRendering = false;

    }

    void SetMaterial(Material mat, string properyName)

    {

        if (mat.HasProperty(properyName))

        {

            if (Shader)

            {

                //Debug.Log("setting ref text for " + GetInstanceID());

                if (Iterations % 2 == 1) //again a hack:)

                {

                    mat.SetTexture(properyName, _reflectionTexture3);

                }

                else

                {

                    mat.SetTexture(properyName, _reflectionTexture2);

                }

            }

            else

            {

                mat.SetTexture(properyName, _reflectionTexture1);

            }

        }

    }

    // Cleanup all the objects we possibly have created

    void OnDisable()

    {

        if (_reflectionTexture1)

        {

            DestroyImmediate(_reflectionTexture1);

            _reflectionTexture1 = null;

        }

        if (_reflectionTexture2)

        {

            DestroyImmediate(_reflectionTexture2);

            _reflectionTexture2 = null;

        }

        if (_reflectionTexture3)

        {

            DestroyImmediate(_reflectionTexture3);

            _reflectionTexture3 = null;

        }

        foreach (DictionaryEntry kvp in _reflectionCameras)

            DestroyImmediate(((Camera)kvp.Value).gameObject);

        _reflectionCameras.Clear();

    }

    private void UpdateCameraModes(Camera src, Camera dest)

    {

        if (dest == null || ReflectionCameraPrefab != null)

            return;

        // set camera to clear the same way as current camera

        if (WorkType == WorkType.Transparent)

        {

            dest.clearFlags = CameraClearFlags.Color;

            dest.backgroundColor = new Color(0, 0, 0, 1); //we will use that to clear background on shader

        }

        else

        {

            dest.clearFlags = src.clearFlags;//CameraClearFlags.SolidColor;  src.clearFlags;

            dest.backgroundColor = src.backgroundColor;

            if (src.clearFlags == CameraClearFlags.Skybox)

            {

                Skybox sky = src.GetComponent(typeof(Skybox)) as Skybox;

                Skybox mysky = dest.GetComponent(typeof(Skybox)) as Skybox;

                if (mysky != null)

                {

                    if (!sky || !sky.material)

                    {

                        mysky.enabled = false;

                    }

                    else

                    {

                        mysky.enabled = true;

                        mysky.material = sky.material;

                    }

                }

            }

        }

        // update other values to match current camera.

        // even if we are supplying custom camera&projection matrices,

        // some of values are used elsewhere (e.g. skybox uses far plane)

        dest.farClipPlane = src.farClipPlane;

        dest.nearClipPlane = src.nearClipPlane;

        dest.orthographic = src.orthographic;

        dest.fieldOfView = src.fieldOfView;

        dest.aspect = src.aspect;

        dest.orthographicSize = src.orthographicSize;

        dest.renderingPath = src.renderingPath;

        dest.allowHDR = src.allowHDR;

        if (WorkType == WorkType.Transparent)

        {

            dest.allowMSAA = false; //!!!!! do not smooth texture!! it is important not to blend corners :)

        }

        else

        {

            dest.allowMSAA = src.allowMSAA;

        }

    }

    // On-demand create any objects we need

    private void CreateMirrorObjects(Camera currentCamera, out Camera reflectionCamera)

    {

        //reflectionCamera = null;

        // Reflection render texture

        if (!_reflectionTexture1 || !_reflectionTexture2 || !_reflectionTexture3 ||

            _oldReflectionTextureSize != TextureSize)

        {

            if (_reflectionTexture1)

                DestroyImmediate(_reflectionTexture1);

            _reflectionTexture1 = new RenderTexture(TextureSize, TextureSize, 24);

            _reflectionTexture1.name = "__MirrorReflection1" + GetInstanceID();

            if (WorkType == WorkType.Transparent)

            {

                _reflectionTexture1.filterMode = FilterMode.Point; //no filter for transparency, do not smooth :)

            }

            _reflectionTexture1.isPowerOfTwo = true;

            _reflectionTexture1.hideFlags = HideFlags.DontSave;

            if (Lod > 0)

            {

                _reflectionTexture1.useMipMap = true;

                _reflectionTexture1.autoGenerateMips = false;

            }

            if (_reflectionTexture2)

                DestroyImmediate(_reflectionTexture2);

            _reflectionTexture2 = new RenderTexture(TextureSize, TextureSize, 24);

            _reflectionTexture2.name = "__MirrorReflection2" + GetInstanceID();

            if (WorkType == WorkType.Transparent)

            {

                _reflectionTexture2.filterMode = FilterMode.Point; //no filter for transparency, do not smooth :)

            }

            _reflectionTexture2.isPowerOfTwo = true;

            _reflectionTexture2.hideFlags = HideFlags.DontSave;

            if (Lod > 0)

            {

                _reflectionTexture2.useMipMap = true;

                _reflectionTexture2.autoGenerateMips = false;

            }

            if (_reflectionTexture3)

                DestroyImmediate(_reflectionTexture3);

            _reflectionTexture3 = new RenderTexture(TextureSize, TextureSize, 24);

            _reflectionTexture3.name = "__MirrorReflection3" + GetInstanceID();

            if (WorkType == WorkType.Transparent)

            {

                _reflectionTexture3.filterMode = FilterMode.Point; //no filter for transparency, do not smooth :)

            }

            _reflectionTexture3.isPowerOfTwo = true;

            _reflectionTexture3.hideFlags = HideFlags.DontSave;

            if (Lod > 0)

            {

                _reflectionTexture3.useMipMap = true;

                _reflectionTexture3.autoGenerateMips = false;

            }

            _oldReflectionTextureSize = TextureSize;

        }

        // Camera for reflection

        if (ReflectionCameraPrefab == null)

        {

            reflectionCamera = _reflectionCameras[currentCamera] as Camera;

            if (!reflectionCamera) // catch both not-in-dictionary and in-dictionary-but-deleted-GO

            {

                GameObject go = new GameObject("Mirror Refl Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(), typeof(Camera), typeof(Skybox));

                reflectionCamera = go.GetComponent<Camera>();

                reflectionCamera.enabled = false;

                reflectionCamera.transform.position = transform.position;

                reflectionCamera.transform.rotation = transform.rotation;

                reflectionCamera.gameObject.AddComponent<FlareLayer>();

                go.hideFlags = HideFlags.HideAndDontSave;

                _reflectionCameras[currentCamera] = reflectionCamera;

            }

        }

        else

        {

            //reflectionCamera = _reflectionCameras[currentCamera] as Camera;

            if (_reflectionCameraPrefabInstance != null)

            {

                reflectionCamera = _reflectionCameraPrefabInstance.GetComponent<Camera>();

            }

            else

                //if (!reflectionCamera) // catch both not-in-dictionary and in-dictionary-but-deleted-GO

            {

                _reflectionCameraPrefabInstance = GameObject.Instantiate(ReflectionCameraPrefab);

                reflectionCamera = _reflectionCameraPrefabInstance.GetComponent<Camera>();

                reflectionCamera.enabled = false;

                //reflectionCamera.transform.position = transform.position;

                //reflectionCamera.transform.rotation = transform.rotation;

                //reflectionCamera.gameObject.AddComponent<FlareLayer>();

                _reflectionCameraPrefabInstance.hideFlags = HideFlags.HideAndDontSave;

                //reflectionCamera = _reflectionCameraPrefabInstance;

            }

        }

    }

    // Given position/normal of the plane, calculates plane in camera space.

    private Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign)

    {

        Vector3 offsetPos = pos + normal * ClipPlaneOffset;

        Matrix4x4 m = cam.worldToCameraMatrix;

        Vector3 cpos = m.MultiplyPoint(offsetPos);

        Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign;

        return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));

    }

    // Calculates reflection matrix around the given plane

    private 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 enum FollowVector

{

    RedX = 1,

    RedX_Negative = 4,

    GreenY = 2,

    GreenY_Negative = 5,

    BlueZ = 3,

    BlueZ_Negative = 6

}

public enum WorkType

{

    Reflect = 1,

    Direct = 2,

    Transparent = 3,

    WaterTop = 4,

    WaterBottom = 5

}

4、新建一个Cylinder对象,挂上对应的脚本,便能看到最终的效果。


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容