镜面反射效果

2018-07-23  本文已影响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 () {
        
    }
}


上一篇下一篇

猜你喜欢

热点阅读