UnityTips 之 矩阵反射

2023-03-20  本文已影响0人  暴走TA

简介: 需要一个 URP 的镜面反射脚本,从网上抄了一个,做了下调整,有些坑点改了一下
来源 https://zhuanlan.zhihu.com/p/559002264
unity版本:20222.1.7fc1

[ExecuteAlways]
public class Reflect: MonoBehaviour
{
    public Vector2Int TexSize = new Vector2Int(960, 540);
    Camera _reflectionCamera;
    RenderTexture _reflectionRT;

    private void OnEnable()
    {
       //生成相机并设置相关rt
        var CameraObj = new GameObject("myCamera");
        _reflectionCamera = CameraObj.AddComponent<Camera>();
        _reflectionCamera.name = "__ReflectCamera__";
        _reflectionCamera.enabled = false;
        if (_reflectionRT == null)
        {
            _reflectionRT = RenderTexture.GetTemporary(TexSize.x, TexSize.y, 0);
            _reflectionRT.name = "__reflectRT__";
            _reflectionRT.depth = 16;
            _reflectionRT.useMipMap = true;
            _reflectionRT.filterMode = FilterMode.Trilinear;
        }
        _reflectionCamera.targetTexture = _reflectionRT;
        Shader.SetGlobalTexture("_ReflectionTex", _reflectionRT);
        //添加相机渲染事件
        RenderPipelineManager.beginCameraRendering += UpdateCamera;
    }
    private void OnDisable()
    {
        //取消相机渲染事件
        RenderPipelineManager.beginCameraRendering -= UpdateCamera;
       //删除相机物体
        if (_reflectionCamera != null)
        {
            DestroyImmediate(_reflectionCamera.gameObject);
        }
       //释放RT 记得置空
        if (_reflectionRT != null)
        {
            RenderTexture.ReleaseTemporary(_reflectionRT);
            _reflectionRT =null;
        }
    }

    private void UpdateCamera(ScriptableRenderContext src, Camera camera)
    {
        if (_reflectionCamera == null)
            return;
        var isSceneCam = false;//考虑场景相机的渲染
        #if UNITY_EDITOR
            isSceneCam = camera == SceneView.lastActiveSceneView.camera;
        #endif
        if (camera == Camera.main||isSceneCam)//之渲染主相机和场景相机
        {
            GL.invertCulling = true;     //反转矩阵会反转面剔除~~
            CameraSetup(camera);
            UniversalRenderPipeline.RenderSingleCamera(src, _reflectionCamera);
            GL.invertCulling = false;//渲染完设置回来
        }
    }
    //设置相机信息
    private void CameraSetup(Camera viewCamera)
    {
        //设置相机基础信息
        _reflectionCamera.aspect = viewCamera.aspect;//设定一样的长宽比
        _reflectionCamera.fieldOfView = viewCamera.fieldOfView;//设置一样的fov 其他需要的设置也可以一样设置过来

        var reflectM = CaculateReflectMatrix();//计算反射矩阵
       //根据参照相机设置其镜像矩阵给反射相机,用来做镜像渲染
        _reflectionCamera.worldToCameraMatrix = viewCamera.worldToCameraMatrix * reflectM;
        //计算反射平面和裁剪矩阵, 用来裁剪对称方向的模型
        var normal = transform.up;
        var d = -Vector3.Dot(normal, transform.position);
        var plane = new Vector4(normal.x, normal.y, normal.z, d);
        var viewSpacePlane = _reflectionCamera.worldToCameraMatrix.inverse.transpose * plane;
        var clipMatrix = _reflectionCamera.CalculateObliqueMatrix(viewSpacePlane);
        _reflectionCamera.projectionMatrix = clipMatrix;
    }
    #if UNITY_EDITOR
    //设置相机的镜像位置,对渲染没啥实际影响,因为反射 相机的矩阵已经被设置过了
     private void Update()
     {
        Vector3 viewerPos = viewCamera.transform.position;
        float reflectHeight = transform.position.y;
        reflectionCamera.transform.position = new Vector3(viewerPos.x, viewerPos.y - 2 * (viewerPos.y - reflectHeight), viewerPos.z);
        reflectionCamera.transform.eulerAngles = new Vector3(-viewCamera.transform.eulerAngles.x, viewCamera.transform.eulerAngles.y, viewCamera.transform.eulerAngles.z);
    }
    #endif
    //本人不会推导这玩意,这个就是计算反射矩阵用的,网上铺天盖地的都是,直接复制
    Matrix4x4 CaculateReflectMatrix()
    {
        var normal = transform.up;
        var d = -Vector3.Dot(normal, transform.position);
        var reflectM = new Matrix4x4();
        reflectM.m00 = 1 - 2 * normal.x * normal.x;
        reflectM.m01 = -2 * normal.x * normal.y;
        reflectM.m02 = -2 * normal.x * normal.z;
        reflectM.m03 = -2 * d * normal.x;

        reflectM.m10 = -2 * normal.x * normal.y;
        reflectM.m11 = 1 - 2 * normal.y * normal.y;
        reflectM.m12 = -2 * normal.y * normal.z;
        reflectM.m13 = -2 * d * normal.y;

        reflectM.m20 = -2 * normal.x * normal.z;
        reflectM.m21 = -2 * normal.y * normal.z;
        reflectM.m22 = 1 - 2 * normal.z * normal.z;
        reflectM.m23 = -2 * d * normal.z;

        reflectM.m30 = 0;
        reflectM.m31 = 0;
        reflectM.m32 = 0;
        reflectM.m33 = 1;
        return reflectM;
    }
}
上一篇下一篇

猜你喜欢

热点阅读