美文网首页
镜面反射效果

镜面反射效果

作者: 星易乾川 | 来源:发表于2018-07-23 18:04 被阅读0次
    镜面反射.jpg 反射矩阵原理.jpg

    知识点概括
    M(model_matrix)模型空间转世界空间矩阵 worldToCameraMatrix
    R(reflac_matrix)反射矩阵 平面的法线向量及平面上的一个点可求得
    V(view_matrix)世界空间转摄像机空间矩阵 CameraToworldMatrix
    P(project_matrix)摄像机矩阵转剪裁空间矩阵 斜视椎体投影与剪裁面求得

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class MirrorReflaction : MonoBehaviour {
        private Camera RefCamera;
        private Material RefMat;
        private RenderTexture ReflTex;
        private Transform Panel;
        private string ReflectTextureName = "_ReflectTex";
        public float clipPlaneOffset = 0;
        // Use this for initialization
        void Start () {
            if (null == RefCamera)
            {
                GameObject go = new GameObject();
                go.name = "reflCamera";
                RefCamera = go.AddComponent<Camera>();
                RefCamera.CopyFrom(Camera.main);
                //RefCamera.fieldOfView *= 1.1f;
                RefCamera.enabled = false;
                RefCamera.clearFlags = CameraClearFlags.SolidColor;
                RefCamera.backgroundColor = new Color(0, 0, 0, 0);
                RefCamera.cullingMask = ~(1 << LayerMask.NameToLayer("Water"));//去除该层
            }
            if (null == RefMat)
            {
                RefMat = this.GetComponent<Renderer>().sharedMaterial;
            }
            if (null == ReflTex)
                ReflTex = new RenderTexture(Mathf.FloorToInt(Camera.main.pixelWidth * 0.5f),
                                            Mathf.FloorToInt(Camera.main.pixelHeight * 0.5f), 24);
            ReflTex.hideFlags = HideFlags.DontSave;//保留对象到新场景
            RefCamera.targetTexture = ReflTex;
            if (null == Panel)
            {
                Panel = transform;
            }
        }
        public void OnWillRenderObject()//当渲染物体之前
        {
            RenderRefection();
        }
    
        void RenderRefection()
        {
            Vector3 normal = Panel.up;
    
            float d = -Vector3.Dot(normal, Panel.position);
            //反射矩阵
            Matrix4x4 refMatrix = new Matrix4x4();
            refMatrix.m00 = 1 - 2 * normal.x * normal.x;
            refMatrix.m01 = -2 * normal.x * normal.y;
            refMatrix.m02 = -2 * normal.x * normal.z;
            refMatrix.m03 = -2 * d * normal.x;
    
            refMatrix.m10 = -2 * normal.x * normal.y;
            refMatrix.m11 = 1 - 2 * normal.y * normal.y;
            refMatrix.m12 = -2 * normal.y * normal.z;
            refMatrix.m13 = -2 * d * normal.y;
    
            refMatrix.m20 = -2 * normal.x * normal.z;
            refMatrix.m21 = -2 * normal.y * normal.z;
            refMatrix.m22 = 1 - 2 * normal.z * normal.z;
            refMatrix.m23 = -2 * d * normal.z;
    
            refMatrix.m30 = 0;
            refMatrix.m31 = 0;
            refMatrix.m32 = 0;
            refMatrix.m33 = 1;
            //1.M(model_matrix)将点从物体坐标系转换到世界坐标系
            //2.进行世界坐标系下将顶点转换到反射点的反射矩阵(在世界坐标系下平面的法线向量和d(d可以通过平面上任意一点求得))
            //3.V(view_matrix)表示将点从世界坐标系变换到视点坐标系(摄像机坐标系)
            //4.P(project_matrix)表示将点从视点坐标系转换到裁剪坐标系
    
            //从世界空间转为摄像机空间
            RefCamera.worldToCameraMatrix = Camera.main.worldToCameraMatrix * refMatrix;
            RefCamera.transform.position = refMatrix.MultiplyPoint(Camera.main.transform.position);
    
            Vector3 forward = Camera.main.transform.forward;
            //      Vector3 up = Camera.main.transform.up;
            forward = refMatrix.MultiplyVector(forward);
            //      up = refMatrix.MultiplyVector (up);
            //      Quaternion refQ = Quaternion.LookRotation (forward, up);
            //      RefCamera.transform.rotation = refQ;
            RefCamera.transform.forward = forward;
    
            //
            Matrix4x4 projM = RefCamera.projectionMatrix;
            //裁剪面
            Vector4 clipPlane = CameraSpacePlane(RefCamera, Panel.position, Panel.up, 1);
            //裁剪空间矩阵
            RefCamera.projectionMatrix = CalculateObliqueMatrix(projM, clipPlane);
    
            GL.invertCulling = true;
            RefCamera.Render();
            GL.invertCulling = false;
    
            RefCamera.targetTexture.wrapMode = TextureWrapMode.Repeat;
            RefMat.SetTexture(ReflectTextureName, RefCamera.targetTexture);
        }
        //摄像机视空间剪裁面
        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));
        }
        public static float Sgn(float a)
        {
            if (a > 0.0F)
            {
                return 1.0F;
            }
            if (a < 0.0F)
            {
                return -1.0F;
            }
            return 0.0F;
        }
        //斜视椎体投影与剪裁面
        public static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 projection, Vector4 clipPlane)
        {
            Vector4 q = projection.inverse * new Vector4(
                Sgn(clipPlane.x),
                Sgn(clipPlane.y),
                1.0F,
                1.0F
                );
            Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q)));
            // third row = clip plane - fourth row
            projection[2] = c.x - projection[3];
            projection[6] = c.y - projection[7];
            projection[10] = c.z - projection[11];
            projection[14] = c.w - projection[15];
    
            return projection;
        }
        // Update is called once per frame
        void Update () {
            
        }
    }
    
    
    

    相关文章

      网友评论

          本文标题:镜面反射效果

          本文链接:https://www.haomeiwen.com/subject/pwvjmftx.html