美文网首页
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 之CacheServer

    一、CacheServer是什么? CacheServer是Unity提供的一个高速缓存服务器,用于存储导入到项目...

  • UnityTips 之 PackageManager

    简介: unity在2018版本就已经有 PackageManager,来管理引擎的功能插件了,有了这个东西,我们...

  • UnityTips 之 只使用光线追踪来计算反射

    简介:光线最终计算虽然准确,无奈每次有变化都会渐进式的刷新窗口,其实传统管线的正常光照效果就已经很不错了。那么我们...

  • 镜面反射的倾斜矩阵

    镜面反射使用倾斜矩阵,是为了解决在反射面下面的物体也会被渲染到反射面上的bug。 解决的办法是把反射平面作为反射相...

  • UnityTips 之 色板

    unity 版本 2018.4.2f1简单介绍一下unity色板的两个实用小功能打开一个unity的基础颜色面板会...

  • UnityTips 之 选择集

    unity 版本 2018.4.2f1 重复选取物体,劳神伤体 相信在工作会遇到这样一个问题,比如场景,要修改一批...

  • UnityTips 之 颜色配置

    简介:可能大家有修改UNTIY一些配色的需求,下面给大家介绍一下UNITY从哪里可以调整引擎编辑器的部分颜色。版本...

  • UnityTips 之 显示模式

    简介: unity 的scene窗口为我们提供了多种显示模式,官方的全局光照部分只讲了一部分,这里做了补全。我们来...

  • UnityTips 之 Prefab 编辑

    简介: 最近在鼓捣2021的时候注意到了unity的prefab在场景中编辑有了新的特性,作者是从2019越级到2...

网友评论

      本文标题:UnityTips 之 矩阵反射

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