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;
}