【Unity】3D模型或粒子渲染在UI上层

方法有很多,我只介绍一种我认为最简单有效的方法,用非常取巧的手段,使用RenderTexture + Camera 在ScrollView里展示3D模型。

效果:

1.首先创建一个RenderTexture用于渲染3D元素,然后在ScrollView里创建一个RawImage,用于把RenderTexture上的内容显示在UI上:

2.代码动态创建一个Camera,用于把3D模型渲染到RenderTexture上:

[SerializeField] RenderTexture renderModelTex = null;//就是上一步创建的RenderTexture
Camera renderCam = null;
Vector2 screenWroldSize;
Vector3 renderCamOffset = Vector3.zero;
Vector3 contentRawPos;

void Awake(){
renderCam = new GameObject("RenderCamera").AddComponent<Camera>();
        renderCam.orthographic = true;
        renderCam.transform.position = new Vector3(0, 0, -10);
        renderCam.transform.rotation = Quaternion.identity;
        renderCam.clearFlags = CameraClearFlags.SolidColor;
        renderCam.cullingMask = LayerMask.GetMask("TransparentFX");
        renderCam.targetTexture = renderModelTex;
        renderImage.GetComponent<RawImage>().texture = renderModelTex;
        screenWroldSize = GF.Instance.uiCam.ViewportToWorldPoint(new Vector3(1, 1, GetComponent<Canvas>().planeDistance));
}

3.创建ScrollView列表元素:

这里为了取巧,使用协程创建列表元素,因为要等Unity 的Layout组件在下一帧自动布局排列完成,然后在排列后的Item位置创建3D模型。

IEnumerator CreateListView(int index)
    {
        //清空滚动列表里的UI item
        GF.UI.RemoveAllChildren(listView.content);
        //清空UI item对应的3D模型
        foreach (var item in skinModelList)
        {
            GF.Entity.HideEntitySafe(item);
        }
        skinModelList.Clear();

        curSelectSkinItem = null;

        List<int> ownSkinList = null;
        int curWearSkin = 0;
        int itemOrder = 0;

        var skinTb = GF.DataTable.GetDataTable<SkinTable>();
        SkinTable[] skinDtRows = skinTb.GetAllDataRows();
//创建N个UI Item
        for (int i = 0; i < skinRowList.Count; i++)
        {
            Instantiate(itemPfb, listView.content);
        }
//需要等下一帧Layout组件自动布局排列完成后再创建模型
        yield return new WaitForEndOfFrame();

        float rectSize = Mathf.Max(listView.viewport.rect.size.x, listView.viewport.rect.size.y);
//动态的将渲染图改变为滚动列表的大小
        renderImage.sizeDelta = new Vector2(rectSize, rectSize);
//同时更新相机视口的大小 保持一致
        var wSize = screenWroldSize.y * (rectSize / this.rectTransform().rect.height);
        renderCam.orthographicSize = wSize;

        var camPos = renderImage.position;
        camPos.z = renderCam.transform.position.z;
        renderCam.transform.position = camPos;
        renderCamOffset = camPos;
//记录滚动列表Content的初始位置, 以便滑动列表时根据Content的位置偏移更新Camera的位置
        contentRawPos = listView.content.position;
        foreach (Transform item in listView.content)
        {
            var skinItem = item.GetComponent<SkinItem>();
            var pos = skinItem.transform.position;
            pos.z = 1;
//在排列好的列表元素位置创建3D模型
            SkinPreviewEntityData eDt = ReferencePool.Acquire<SkinPreviewEntityData>().FillArgs(index, 1);
            eDt.Position = pos + itemPosOffset;
            eDt.Rotation = itemRotation;
            eDt.Scale = itemScale;
            var skinModelId = GF.Entity.ShowEntity(typeof(SkinPreviewEntity), skinItem.SkinData.PrefabName, Const.EntityGroup.ScrollViewModel, eDt);
            skinModelList.Add(skinModelId);
        }
    }

4.使Camera跟随ScrollView的滑动,从而达到3D模型跟随列表滚动的效果:

public void OnScrollValue(Vector2 pos)
    {
        Vector3 camPos = renderCamOffset - (listView.content.position - contentRawPos);
        renderCam.transform.position = camPos;
    }

把此函数拖到ScrollView的滚动事件上就大功告成了。

总解:通过此方式可以完美的把3D模型以UI元素的形式渲染到UI上层,不用考虑3D模型的遮罩问题。让Camera跟随ScrollView的Content节点移动,与Layout组件互不影响,随便怎么布局,最终模型展示的位置跟随UI Item创建的位置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值