【m】1111
This commit is contained in:
191
Assets/06.UIFarme/RunTime/UIFramework/UIModel/UIModelManager.cs
Normal file
191
Assets/06.UIFarme/RunTime/UIFramework/UIModel/UIModelManager.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Resources;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using YooAsset;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
public class UIModelManager : Singleton<UIModelManager>
|
||||
{
|
||||
private Stack<Camera> m_CameraPool = new Stack<Camera>();
|
||||
private Stack<int> m_IndexPool = new Stack<int>();
|
||||
private int m_PoolCount = 0;
|
||||
private Camera m_UICamera;
|
||||
|
||||
private Transform m_UIModelRoot;
|
||||
private Light m_UIModelLight;
|
||||
|
||||
public Camera UICamera => m_UICamera;
|
||||
|
||||
public override void OnInitialize()
|
||||
{
|
||||
base.OnInitialize();
|
||||
|
||||
//m_UICamera = GameObject.Find("UICamera").GetOrAddComponent<Camera>();
|
||||
|
||||
m_UIModelRoot = new GameObject("UIModelRoot").transform;
|
||||
m_UIModelRoot.SetParentEx(null);
|
||||
GameObject.DontDestroyOnLoad(m_UIModelRoot);
|
||||
|
||||
m_UIModelLight = new GameObject("UIModelLight").GetOrAddComponent<Light>();
|
||||
m_UIModelLight.transform.SetParentEx(m_UIModelRoot);
|
||||
|
||||
m_UIModelLight.transform.localEulerAngles = new Vector3(36, 30, 0);
|
||||
m_UIModelLight.cookieSize = 10;
|
||||
m_UIModelLight.type = LightType.Directional;
|
||||
m_UIModelLight.cullingMask = 1 << Layer.UI | 1 << Layer.UIRenderToTarget;
|
||||
m_UIModelLight.shadows = LightShadows.None;
|
||||
|
||||
m_UIModelLight.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载一个模型到一张RawImage上
|
||||
/// </summary>
|
||||
public async UniTask LoadModelToRawImage(string path, RawImage rawImage, bool canDrag = true, Vector3 offset = default,
|
||||
Quaternion rot = default, Vector3 scale = default, bool isOrth = true, float orthSizeOrFOV = 1,
|
||||
Action<UIRenderToTexture, GameObject> callback = null)
|
||||
{
|
||||
if (rawImage == null)
|
||||
{
|
||||
Debug.LogError("RawImage Is Null!");
|
||||
return;
|
||||
}
|
||||
|
||||
rawImage.enabled = false;
|
||||
var handle = YooAssets.LoadAssetSync<GameObject>(path);
|
||||
await handle.Task;
|
||||
GameObject go = handle.GetAssetObject<GameObject>();
|
||||
|
||||
UnLoadModelByRawImage(rawImage);
|
||||
rawImage.enabled = true;
|
||||
LoadModelToRawImage(go, rawImage, canDrag, offset, rot, scale, isOrth, orthSizeOrFOV, callback);
|
||||
}
|
||||
|
||||
public void LoadModelToRawImage(GameObject go, RawImage rawImage, bool canDrag, Vector3 offset = default,
|
||||
Quaternion rot = default, Vector3 scale = default, bool isOrth = true, float orthSizeOrFOV = 1,
|
||||
Action<UIRenderToTexture, GameObject> callback = null)
|
||||
{
|
||||
if (go != null)
|
||||
{
|
||||
UIRenderToTexture renderToTexture = rawImage.GetOrAddComponent<UIRenderToTexture>();
|
||||
Vector3 pos;
|
||||
int index = 0;
|
||||
if (renderToTexture.Targets == null || renderToTexture.Targets.Count == 0)
|
||||
{
|
||||
index = m_IndexPool.Count > 0 ? m_IndexPool.Pop() : m_PoolCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
index = renderToTexture.Index;
|
||||
}
|
||||
|
||||
pos = new Vector3(100 * index, -10000, 0);
|
||||
renderToTexture.Init(pos, isOrth, orthSizeOrFOV, index);
|
||||
UpdateLight();
|
||||
|
||||
go.SetLayerRecursively(Layer.UIRenderToTarget);
|
||||
go.transform.SetParent(m_UIModelRoot);
|
||||
go.transform.localPosition = pos + offset;
|
||||
go.transform.localScale = scale == default ? Vector3.one : scale;
|
||||
go.transform.rotation = rot;
|
||||
renderToTexture.AddTarget(go, canDrag);
|
||||
callback?.Invoke(renderToTexture, go);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载单个
|
||||
/// </summary>
|
||||
public void UnLoadModelByRawImage(RawImage rawImage, GameObject go)
|
||||
{
|
||||
if (rawImage != null && go != null)
|
||||
{
|
||||
UIRenderToTexture renderToTexture = rawImage.GetComponent<UIRenderToTexture>();
|
||||
int id = go.GetInstanceID();
|
||||
if (renderToTexture != null && renderToTexture.Targets != null &&
|
||||
renderToTexture.Targets.ContainsKey(id))
|
||||
{
|
||||
renderToTexture.Targets.Remove(id);
|
||||
//ResourceManager.Instance.GetResourceCore(UIConfig.UIPackageName).Recycle(go);
|
||||
if (renderToTexture.Targets.Count == 0)
|
||||
{
|
||||
m_IndexPool.Push(renderToTexture.Index);
|
||||
renderToTexture.ResetTarget();
|
||||
}
|
||||
|
||||
UpdateLight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 卸载所有
|
||||
/// </summary>
|
||||
public void UnLoadModelByRawImage(RawImage rawImage, bool recycleGo = true)
|
||||
{
|
||||
if (rawImage != null)
|
||||
{
|
||||
UIRenderToTexture renderToTexture = rawImage.GetComponent<UIRenderToTexture>();
|
||||
if (renderToTexture != null && renderToTexture.Targets != null && renderToTexture.Targets.Count > 0)
|
||||
{
|
||||
if (recycleGo)
|
||||
{
|
||||
foreach (var target in renderToTexture.Targets.Values)
|
||||
{
|
||||
// ResourceManager.Instance.GetResourceCore(UIConfig.UIPackageName).Recycle(target.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
m_IndexPool.Push(renderToTexture.Index);
|
||||
renderToTexture.ResetTarget();
|
||||
UpdateLight();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLight()
|
||||
{
|
||||
m_UIModelLight.gameObject.SetActive(m_CameraPool.Count < m_PoolCount);
|
||||
}
|
||||
|
||||
public Camera SpawnCamera()
|
||||
{
|
||||
if (m_CameraPool.Count > 0)
|
||||
{
|
||||
Camera camera = m_CameraPool.Pop();
|
||||
camera.gameObject.SetActive(true);
|
||||
return camera;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject go = new GameObject("CameraRTT");
|
||||
go.transform.SetParentEx(m_UIModelRoot);
|
||||
Camera camera = go.GetOrAddComponent<Camera>();
|
||||
camera.fieldOfView = 30;
|
||||
camera.allowHDR = false;
|
||||
camera.backgroundColor = Color.clear;
|
||||
camera.useOcclusionCulling = false;
|
||||
camera.clearFlags = CameraClearFlags.SolidColor;
|
||||
camera.cullingMask = 1 << Layer.UIRenderToTarget;
|
||||
camera.farClipPlane = 30;
|
||||
camera.orthographicSize = 1;
|
||||
|
||||
return camera;
|
||||
}
|
||||
}
|
||||
|
||||
public void RecyleCamera(Camera camera)
|
||||
{
|
||||
if (camera != null)
|
||||
{
|
||||
camera.targetTexture = null;
|
||||
camera.gameObject.SetActive(false);
|
||||
m_CameraPool.Push(camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ef5008611a90c147a4a9d40cc4c0cc0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,215 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Experimental.Rendering;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Stary.Evo
|
||||
{
|
||||
|
||||
public class UIRenderToTexture : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler, IPointerClickHandler
|
||||
{
|
||||
public struct Target
|
||||
{
|
||||
public GameObject gameObject;
|
||||
public bool canDrag;
|
||||
}
|
||||
|
||||
private Camera m_Camera;
|
||||
private RawImage m_RawImage;
|
||||
private RenderTexture m_RenderTexture;
|
||||
private Dictionary<int, Target> m_Targets = new Dictionary<int, Target>();
|
||||
private int m_Index = -1;
|
||||
private Transform m_DragTarget;
|
||||
private float m_orthographicSize = 1;
|
||||
|
||||
public Camera Camera => m_Camera;
|
||||
public Dictionary<int, Target> Targets => m_Targets;
|
||||
public int Index => m_Index;
|
||||
/// <summary>
|
||||
/// 目标被点击
|
||||
/// </summary>
|
||||
public event Action<GameObject> OnTargetClick;
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (m_Camera != null)
|
||||
UIModelManager.Instance.RecyleCamera(m_Camera);
|
||||
ReleaseRenderTexture();
|
||||
}
|
||||
|
||||
|
||||
public void Init(Vector3 vec, bool isOrth, float orth, int index)
|
||||
{
|
||||
InitCamera(isOrth, orth);
|
||||
m_Index = index;
|
||||
if (m_Camera)
|
||||
{
|
||||
m_Camera.transform.localPosition = vec + new Vector3(0, 0, 20);
|
||||
m_Camera.transform.localEulerAngles = new Vector3(0, 180, 0);
|
||||
}
|
||||
|
||||
if (m_RawImage == null)
|
||||
m_RawImage = GetComponent<RawImage>();
|
||||
|
||||
if (m_RenderTexture == null)
|
||||
{
|
||||
m_RenderTexture = RenderTexture.GetTemporary((int)m_RawImage.rectTransform.rect.width, (int)m_RawImage.rectTransform.rect.height, 1, RenderTextureFormat.ARGB32);
|
||||
m_RenderTexture.name = "UIRenderToTexture";
|
||||
}
|
||||
m_Camera.targetTexture = m_RenderTexture;
|
||||
m_RawImage.texture = m_RenderTexture;
|
||||
}
|
||||
|
||||
private void InitCamera(bool isOrth, float orth)
|
||||
{
|
||||
if (m_Camera == null)
|
||||
{
|
||||
m_Camera = UIModelManager.Instance.SpawnCamera();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Camera.gameObject.SetActive(true);
|
||||
}
|
||||
m_Camera.orthographic = isOrth;
|
||||
m_Camera.orthographicSize = orth;
|
||||
m_Camera.fieldOfView = orth;
|
||||
m_orthographicSize = orth;
|
||||
}
|
||||
|
||||
private void ReleaseRenderTexture()
|
||||
{
|
||||
if (m_RenderTexture != null)
|
||||
{
|
||||
RenderTexture.ReleaseTemporary(m_RenderTexture);
|
||||
m_RenderTexture = null;
|
||||
m_RawImage.texture = null;
|
||||
}
|
||||
}
|
||||
public bool AddTarget(GameObject target, bool canDrag)
|
||||
{
|
||||
if (target)
|
||||
{
|
||||
if (m_Targets == null)
|
||||
m_Targets = new Dictionary<int, Target>();
|
||||
|
||||
int id = target.GetInstanceID();
|
||||
if (!m_Targets.ContainsKey(id))
|
||||
{
|
||||
m_Targets.Add(id, new Target { gameObject = target, canDrag = canDrag });
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ResetTarget()
|
||||
{
|
||||
m_Targets.Clear();
|
||||
if (m_Camera != null)
|
||||
{
|
||||
UIModelManager.Instance.RecyleCamera(m_Camera);
|
||||
m_Camera = null;
|
||||
}
|
||||
m_Index = -1;
|
||||
ReleaseRenderTexture();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (m_Targets != null)
|
||||
{
|
||||
foreach (var target in m_Targets.Values)
|
||||
{
|
||||
if (m_DragTarget == null || m_DragTarget.gameObject != target.gameObject)
|
||||
target.gameObject.transform.rotation = Quaternion.Lerp(target.gameObject.transform.rotation, Quaternion.identity, Time.deltaTime * 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetClickTarget(Vector2 clickPos)
|
||||
{
|
||||
if (m_Targets.Count == 1)
|
||||
{
|
||||
foreach (var item in m_Targets.Values)
|
||||
{
|
||||
m_DragTarget = item.gameObject.transform;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 通过射线检测当前点击的模型
|
||||
// 拿到点击位置与UI位置的偏移百分比
|
||||
Camera uiCamera = UIModelManager.Instance.UICamera;
|
||||
float width = m_RawImage.rectTransform.rect.width;
|
||||
float height = m_RawImage.rectTransform.rect.height;
|
||||
Vector2 screenPos = RectTransformUtility.WorldToScreenPoint(uiCamera, transform.position);
|
||||
screenPos += new Vector2(width * (0.5f - m_RawImage.rectTransform.pivot.x), height * (0.5f - m_RawImage.rectTransform.pivot.y));
|
||||
Vector2 offset = clickPos - screenPos;
|
||||
offset = new Vector2(offset.x / width, offset.y / height);
|
||||
if (m_Camera.orthographic)
|
||||
{
|
||||
// 正交相机的渲染大小height=size*2, width = 宽高比*height
|
||||
float screenHeight = m_Camera.orthographicSize * 2;
|
||||
float screenWidth = m_Camera.pixelWidth * 1.0f / m_Camera.pixelHeight * screenHeight;
|
||||
Vector3 startPoint = m_Camera.transform.position + m_Camera.transform.right * offset.x * screenWidth + m_Camera.transform.up * offset.y * screenHeight;
|
||||
|
||||
Debug.DrawLine(startPoint, startPoint + m_Camera.transform.forward * 100, Color.red, 5f);
|
||||
if (Physics.Raycast(startPoint, m_Camera.transform.forward, out RaycastHit hit, 100, 1 << Layer.UIRenderToTarget))
|
||||
{
|
||||
m_DragTarget = hit.transform;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 透视相机通过FOV和near可以求height, width同正交相机
|
||||
float screenHeight = Mathf.Tan(m_Camera.fieldOfView * 0.5f * Mathf.Deg2Rad) * m_Camera.nearClipPlane * 2;
|
||||
float screenWidth = m_Camera.pixelWidth * 1.0f / m_Camera.pixelHeight * screenHeight;
|
||||
Vector3 endPoint = m_Camera.transform.position + m_Camera.transform.forward * m_Camera.nearClipPlane
|
||||
+ m_Camera.transform.right * offset.x * screenWidth + m_Camera.transform.up * offset.y * screenHeight;
|
||||
Vector3 dir = (endPoint - m_Camera.transform.position).normalized;
|
||||
|
||||
Debug.DrawLine(m_Camera.transform.position, endPoint, Color.red, 5f);
|
||||
if (Physics.Raycast(m_Camera.transform.position, dir, out RaycastHit hit, m_Camera.farClipPlane, 1 << Layer.UIRenderToTarget))
|
||||
{
|
||||
m_DragTarget = hit.transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
m_DragTarget = null;
|
||||
SetClickTarget(eventData.position);
|
||||
|
||||
// 不能拖拽时置空
|
||||
if (m_DragTarget != null && m_Targets.TryGetValue(m_DragTarget.GetInstanceID(), out Target target) && !target.canDrag)
|
||||
{
|
||||
m_DragTarget = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (m_DragTarget != null)
|
||||
m_DragTarget.localEulerAngles -= new Vector3(0, eventData.delta.x, 0);
|
||||
}
|
||||
|
||||
public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
m_DragTarget = null;
|
||||
}
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
{
|
||||
m_DragTarget = null;
|
||||
SetClickTarget(eventData.position);
|
||||
|
||||
if (m_DragTarget != null)
|
||||
{
|
||||
// 点中模型,发送事件或者其他操作
|
||||
OnTargetClick?.Invoke(m_DragTarget.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0330a7f066ad9324ba9aef4e9041d15f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user