美文网首页
UnityTips 之 矩阵反射

UnityTips 之 矩阵反射

作者: 暴走TA | 来源:发表于2023-03-20 16:24 被阅读0次

    简介: 需要一个 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;
        }
    }
    

    相关文章

      网友评论

          本文标题:UnityTips 之 矩阵反射

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