3D模型在UI中的RenderTexture显示

通常简单的做法
用一个Orthographic相机来做UI相机,Canvas的RenderMode用ScreenSpace-Camera . 这种直角相机照射的3D模型显示有问题,所以需要另外一个Perspective的锥形透视相机来单独照射模型。UI的直角相机设置CullingMask不照射模型。Perspective相机可以用SolidColor模式,背景色的alpha设置为0。
这样的简单做法就可以满足基本的需求了。

上面的做法的问题就是,如果有两个界面重叠都有3D模型,那么就会出现层次渲染问题。
那么进一步优化,给相机加RenderTexture,然后把透视相机拍摄的图像挂载在RawImage里问题就解决了。
创建一个RenderTexture,默认大小是256x256的,如果要清晰点可以设置成1024x1024。

不同的手机分辨率不同的,可能带来RawImage大小不同导致位置不对的问题。
我的CanvasScaler的UIScaleMode设置的是ScaleWithScreenSize.
Reference Resolution x:1080 y:1920

所以我想我只要给UI中心放一张RawImage来呈现Render。能动态计算出RawImage的宽和高就可以了。
我的Canvas的PlaneDistance设置的10,所以相机刚好距离Canvas10米的位置,锥形透视相机在UI直角主相机的子级,本地坐标是0。方便观察和计算。
首先计算出透视相机刚好在UI的视口的等距离的4个点的位置,如图:黄色的框就是计算出的位置。
在这里插入图片描述
计算这个网上有很多代码,贴一个上来。

Vector3[] GetCorners(float distance)
    {
        Vector3[] corners = new Vector3[4];
        Transform tx = theCamera.transform;
        float halfFOV = (theCamera.fieldOfView * 0.5f) * Mathf.Deg2Rad;
        float aspect = theCamera.aspect;

        float height = distance * Mathf.Tan(halfFOV);
        float width = height * aspect;

        // UpperLeft
        corners[0] = tx.position - (tx.right * width);
        corners[0] += tx.up * height;
        corners[0] += tx.forward * distance;

        // UpperRight
        corners[1] = tx.position + (tx.right * width);
        corners[1] += tx.up * height;
        corners[1] += tx.forward * distance;

        // LowerLeft
        corners[2] = tx.position - (tx.right * width);
        corners[2] -= tx.up * height;
        corners[2] += tx.forward * distance;

        // LowerRight
        corners[3] = tx.position + (tx.right * width);
        corners[3] -= tx.up * height;
        corners[3] += tx.forward * distance;

        Debug.Log("0:"+corners[0] + "UpperLeft -> UpperRight dis:" + Vector3.Distance(corners[0], corners[1]));
        Debug.Log("1:" + corners[1] + "UpperRight -> LowerRight dis:" + Vector3.Distance(corners[1], corners[3]));
        Debug.Log("2:" + corners[2] + "LowerRight -> LowerLeft dis:" + Vector3.Distance(corners[3], corners[2]));
        Debug.Log("3:" + corners[3] + "LowerLeft -> UpperLeft dis:" + Vector3.Distance(corners[2], corners[0]));

        Debug.DrawLine(corners[0], corners[1], Color.yellow ) ; // UpperLeft -> UpperRight
        Debug.DrawLine(corners[1], corners[3], Color.yellow); // UpperRight -> LowerRight
        Debug.DrawLine(corners[3], corners[2], Color.yellow); // LowerRight -> LowerLeft
        Debug.DrawLine(corners[2], corners[0], Color.yellow); // LowerLeft -> UpperLeft
        }

观察输出坐标发现4个边之间距离是相同的,因为我们的相机没有改过ViewportRect相关参数。

所以我们只用取左上角的一个点就可以计算出RawImage的宽度和高度。
下面的代码就很简单就计算出来了。

            Vector3 scrPos = theUICamer.WorldToScreenPoint(corners[0]);  //计算左上角的点在UI相机中的位置
            float w = (Mathf.Abs(scrPos.x) + Screen.width / 2) * (1080f / Screen.width) * 2; //计算在当前分辨率的宽度 1080是CanvasScaler的x


            Debug.Log("lt:" + theUICamer.WorldToScreenPoint(corners[0]));
            Debug.Log("w:" + w);

            if (rawimage != null)
            {
                rawimage.sizeDelta = new Vector2(w,w);
            }

这样我们把rawimage放在UI正中心就可以正确的显示RenderTexture里的内容了。

另外可能还遇到一些问题
如果模型不动,可以用相机的Depth模式。如果动可能有重影,就改成SolidColor。但是对于半透明效果的,锥形透视相机可能不能正常显示,可以加一个2D Sprite放在模型后方,否则alpha Blend不会计算 , 具体怎么做后面有空在研究。如果是纯色还好,如果有底图那么可能要计算2D Sprite的位置和大小.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值