Unity进阶技术

Unity中将3D物体显示在UI上

2021-09-03  本文已影响0人  全新的饭

思路

将Camera捕捉到的画面通过RenderTexture传递给UI的RawIamge。

方法

制作一个Mgr:外部(RawImg)传入key(name)和要显示的3D物体,返回给外部一个RenderTexture,让外部显示在RawImg上。

代码

使用示意

modelInUIInfo = Render3DModelInUIMgr.Instance.GetModelInUIInfo(name, prefab);
rawImage.texture = modelInUIInfo.RenderTexture;

Render3DModelInUIMgr

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 将3d模型渲染到UI上
/// </summary>
public class Render3DModelInUIMgr
{
    public static Render3DModelInUIMgr Instance
    {
        get 
        {
            if (_instance == null)
            {
                _instance = new Render3DModelInUIMgr();
                _instance.Init();
            }

            return _instance;
        }
    }
    private static Render3DModelInUIMgr _instance;

    private Dictionary<string, ModelInUIInfo> _uiModelInfoDict;
    private GameObject _rootGo;
    private int _curCnt;
    private GameObject _prefabTemplate;
    private const float PosXInterval = 50;
    private const string PrefabTemplateResourcePath = "Actors/Actor2001";

    private void Init()
    {
        _uiModelInfoDict = new Dictionary<string, ModelInUIInfo>();
        _rootGo = new GameObject(nameof(Render3DModelInUIMgr));
        _rootGo.transform.position = Vector3.one * 1000;
        _curCnt = 0;
        _prefabTemplate = Resources.Load<GameObject>(PrefabTemplateResourcePath);
    }

    public void Clear()
    {
        _curCnt = 0;
        if (_uiModelInfoDict != null && _uiModelInfoDict.Keys.Count > 0)
        {
            foreach (var value in _uiModelInfoDict.Values)
            {
                value.Destroy();
            }
            _uiModelInfoDict.Clear();
        }
    }

    public ModelInUIInfo GetModelInUIInfo(string name, GameObject prefab)
    {
        ModelInUIInfo modelInUIInfo = null;

        if (_uiModelInfoDict.ContainsKey(name))
        {
            modelInUIInfo = _uiModelInfoDict[name];
        }
        else
        {
            modelInUIInfo = new ModelInUIInfo(name, prefab ?? _prefabTemplate, Vector3.right * _curCnt * PosXInterval, _rootGo.transform);
            _uiModelInfoDict.Add(name, modelInUIInfo);
            _curCnt++;
        }

        return modelInUIInfo;
    }
}

public class ModelInUIInfo
{ 
    public GameObject GO{ get; private set; }

    private GameObject _modelGO;
    public RenderTexture RenderTexture{ get; private set; }
    private Camera _cam;
    private Animator _anim;
    private string _name;

    public ModelInUIInfo(string name, GameObject prefab, Vector3 localPos, Transform parent)
    {
        _name = name;

        GameObject GO = new GameObject(name);
        GO.transform.SetParent(parent);
        GO.transform.localPosition = localPos;

        _cam = GO.AddComponent<Camera>();
        _cam.clearFlags = CameraClearFlags.SolidColor;
        _cam.backgroundColor = Color.clear;
        _cam.nearClipPlane = 0.3f;
        _cam.farClipPlane = 10f;
        _cam.orthographic = true;
        _cam.orthographicSize = 0.5f;

        RenderTexture = new RenderTexture(256, 256, 16);
        _cam.targetTexture = RenderTexture;

        _modelGO = GameObject.Instantiate(prefab, GO.transform);
        _modelGO.transform.localPosition = new Vector3(0, -0.45f, 5f);
        _modelGO.transform.localEulerAngles = Vector3.up * -150f;
        _modelGO.transform.localScale = Vector3.one;
        _anim = _modelGO.GetComponentInChildren<Animator>();
    }

    public void TriggerAnim(string animTriggerName)
    {
        _anim?.SetTrigger(animTriggerName);
    }

    public void Destroy()
    {
        GameObject.Destroy(RenderTexture);
        GameObject.Destroy(GO);
    }
}

改良版:RenderGoInUISys.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 将GO渲染到RenderTexture上,以便能通过UI的RawImg展示
/// </summary>
public class RenderGoInUISys
{
    public static RenderGoInUISys Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new RenderGoInUISys();
            }
            return _instance;
        }
        private set
        {
            _instance = value;
        }
    }
    private static RenderGoInUISys _instance;

    private Dictionary<string, RenderGoInUIElement> _elementDict;
    private GameObject _rootGo;
    private const float PosXInterval = 50;

    private RenderGoInUIElementData DefaultElementData
    {
        get
        {
            var data = new RenderGoInUIElementData();
            data.CameNearClipPlane = 0.3f;
            data.CamFarClipPlane = 10f;
            data.CamOrthographicSize = 0.3f;
            data.RTSize = Vector2Int.one * 256;
            data.GOLocalPos = new Vector3(0, -0.45f, 5f);
            data.GOLocalEulerAngles = Vector3.up * -150f;
            data.GOLocalScale = Vector3.one;

            return data;
        }
    }

    private RenderGoInUISys()
    {
        InitElementDict();
        _rootGo = new GameObject(nameof(RenderGoInUISys));
        _rootGo.transform.position = Vector3.one * 1000;

        void InitElementDict()
        {
            _elementDict = new Dictionary<string, RenderGoInUIElement>();
        }
    }

    public void Destroy()
    {
        DestroyElementDict();
        GameObject.Destroy(_rootGo);

        Instance = null;

        void DestroyElementDict()
        {
            ClearElementDict();
            _elementDict = null;
        }
    }

    private void ClearElementDict()
    {
        if (_elementDict != null)
        { 
            foreach(var element in _elementDict.Values)
            {
                element.Destroy();
            }
            _elementDict.Clear();
        }
    }

    public RenderGoInUIElement GetElement(string name, GameObject goTemplate)
    { 
        if (!_elementDict.TryGetValue(name, out RenderGoInUIElement element))
        {
            element = new RenderGoInUIElement(name, goTemplate, DefaultElementData, _rootGo.transform, Vector3.right * _elementDict.Keys.Count * PosXInterval);
            _elementDict.Add(name, element);
        }
        return element;
    }
}

public class RenderGoInUIElement
{
    private string _name;
    public GameObject GO { get; private set; }
    private GameObject _elementGo;
    public RenderTexture RenderTexture { get; private set; }
    private Camera _cam;

    public RenderGoInUIElement(string name, GameObject goTemplate, RenderGoInUIElementData data, Transform parent, Vector3 localPos)
    {
        _name = name;

        GameObject GO = new GameObject(name);
        GO.transform.SetParent(parent);
        GO.transform.localPosition = localPos;

        _cam = GO.AddComponent<Camera>();
        _cam.clearFlags = CameraClearFlags.SolidColor;
        _cam.backgroundColor = Color.clear;
        _cam.nearClipPlane = data.CameNearClipPlane;
        _cam.farClipPlane = data.CamFarClipPlane;
        _cam.orthographic = true;
        _cam.orthographicSize = data.CamOrthographicSize;

        RenderTexture = new RenderTexture(data.RTSize.x, data.RTSize.y, 16);
        _cam.targetTexture = RenderTexture;

        _elementGo = GameObject.Instantiate(goTemplate, GO.transform);
        ChangeElementGoLocalPos(data.GOLocalPos);
        ChangeElementGoLocalEulerAngles(data.GOLocalEulerAngles);
        ChangeElementGoLocalScale(data.GOLocalScale);
    }

    public void ChangeAnim(RuntimeAnimatorController rac)
    {
        var anim = _elementGo.GetComponentInChildren<Animator>();
        if (anim == null)
        {
            anim = _elementGo.AddComponent<Animator>();
        }
        anim.runtimeAnimatorController = rac;
    }

    public void ChangeElementGoLocalPos(Vector3 localPos)
    {
        _elementGo.transform.localPosition = localPos;
    }
    public void ChangeElementGoLocalEulerAngles(Vector3 lcoalEulerAnglers)
    {
        _elementGo.transform.localEulerAngles = lcoalEulerAnglers;
    }
    public void ChangeElementGoLocalScale(Vector3 localScale)
    {
        _elementGo.transform.localScale = localScale;
    }

    public void Destroy()
    {
        GameObject.Destroy(GO);
        GameObject.Destroy(RenderTexture);
    }
}

// 生成 RenderGoInUIElement 所需的一些数据
public struct RenderGoInUIElementData
{
    public float CameNearClipPlane;
    public float CamFarClipPlane;

    public float CamOrthographicSize;

    public Vector2Int RTSize;
    public Vector3 GOLocalPos;
    public Vector3 GOLocalEulerAngles;
    public Vector3 GOLocalScale;
}
上一篇 下一篇

猜你喜欢

热点阅读