Unity中如何通过UI显示3D模型解决方案?

需求:实现将3D模型显示在2DUI上面,实现王者荣耀英雄商城之中英雄展示功能,3D模型可以旋转,添加特效等正常3D功能。

使用RenderTexture 和RawImage做相机映射

效果:

那些黑圈圈就是例子特效哦。

 实现:

  1. Project面板创建一个RawImage
  2. 创建一个Camera,通过设置渲染模式控制模型显示的
  3. 创建一个RenderTexture
  4. 创建一个Cube,设置Layer为指定的布局,比如Model
  5. 将c创建的RenderTexture拖到a创建的RawImage的Texture属性里面
  6. 将c创建的RenderTexture拖到b创建的Camera的Target Texture属性里面
  7. 设置b创建的Camera的Clear Flags 为Solid Color,设置Background属性透明度为0
  8. 之后可以在Canvas里面设置a创建的RawImage的布局和大小来调整相应3D模型

优点:

       可以多模型渲染,可以渲染包括粒子在内的各种3D模型,如果需要显示粒子特效,需要针对性开发对应Shader控制渲染混合方式(如:Blend One OneMinusSrcAlpha),可以再任何UI需要的地方显示,完全和UI一样,层级顺序,列表中显示模型,裁切等等都很方便。

缺点:

       美术效果上,色差问题,和例子效果问题,局限性太大,模型数量不能太多,如果需要实现交互功能也比较麻烦,不能直接使用UI的交互逻辑,需要其他组件的配合,如果人物身上有一些特殊的效果,比如outline描边这样的,放在RenderTexture上就是达不到效果。

使用Screen Space Camera渲染摄像机

效果:

实现:

  1. 创建Canvas1,用来存放UI资源
  2. 创建Canvas2,用来存放3D模型资源,实现UI交互
  3. 将创建的两个Canvas的Render Mode设置为Screen Space –Camera
  4. 将两个Canvas的Render Camera设为同一个相机
  5. 通过调整Camera的Plane Distance控制哪个在前哪个在后面

优点:

       模型可挂载在Canvas底下,也可以直接在场景中创建,调整大小位置,不影响模型本身的效果显示,和正常3D场景一样,模型本身完全不受限制。

缺点:

       需要去控制Canvas的深度值,有很多问题实现不了,UI上盖模型,模型上盖UI,滑动列表中滑动裁切,需要和场景中模型做分离处理,不然容易混到一块分不清

使用世界空间的UI和模型绑定

实现:

  1. 创建Canvas
  2. 更改Canvas的RenderMode为WorldSpace
  3. 之后更改Canvas的大小和位置调整到3D模型的后面

优点:

UI完全跟3D组件一样,可以摆在任意位置和任意模型之后,自由度很大。

缺点:

        UI交互功能很麻烦,UI无法适配屏幕大小显示,需要创建整体背景UI的时候还需要将新的Canvas设置为Screen Space Camera模式

在这个实现中比较重要的一点是如果透过UI将点击事件穿透下去,让模型也可以接受到点击事件,这时候我们就需要在UI上挂一个脚本,当接受到点击事件的时候调用PassEvent将事件传下去。

using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using System.Collections.Generic;
 
public class Test : MonoBehaviour,IPointerClickHandler ,IPointerDownHandler,IPointerUpHandler
{ 
 
    //监听按下
    public void OnPointerDown(PointerEventData eventData)
    {
        PassEvent(eventData,ExecuteEvents.pointerDownHandler);
    }
 
    //监听抬起
    public void OnPointerUp(PointerEventData eventData)
    {
        PassEvent(eventData,ExecuteEvents.pointerUpHandler);
    }
 
    //监听点击
    public void OnPointerClick(PointerEventData eventData)
    {
        PassEvent(eventData,ExecuteEvents.submitHandler);
        PassEvent(eventData,ExecuteEvents.pointerClickHandler);
    }
 
 
    //把事件透下去
    public void  PassEvent<T>(PointerEventData data,ExecuteEvents.EventFunction<T> function)
        where T : IEventSystemHandler
    {
        List<RaycastResult> results = new List<RaycastResult>();
        EventSystem.current.RaycastAll(data, results); 
        GameObject current = data.pointerCurrentRaycast.gameObject ;
        for(int i =0; i< results.Count;i++)
        {
            if(current!= results[i].gameObject)
            {
                ExecuteEvents.Execute(results[i].gameObject, data,function);
                //RaycastAll后ugui会自己排序,如果你只想响应透下去的最近的一个响应,这里ExecuteEvents.Execute后直接break就行。
            }
        }
    }
 
 
}

如有不准确之处,欢迎大家批评加改正哈。。。 

参考链接:

Unity3D研究院之将UI的点击事件渗透下去(九十) | 雨松MOMO程序研究院 (xuanyusong.com)

猜你喜欢

转载自blog.csdn.net/a1191835397/article/details/122385098
今日推荐