Files
XericLibrary-WebGL-Publish/Runtime/Blueprint/Canvas/ScreenSpaceBlueprintCanvas.cs
T
2026-07-30 09:18:26 +08:00

123 lines
4.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
namespace XericLibrary.Runtime.Blueprint.Canvas
{
/// <summary>
/// 屏幕空间蓝图画布实现,基于 UGUI Canvas。
/// <para>
/// 所有坐标转换统一通过 <see cref="RectTransformUtility"/> 完成,
/// 以 <see cref="_renderRoot"/> RectTransform 为坐标基准,
/// 不依赖蓝图自身的 RectTransform 是否撑满全屏。
/// </para>
/// <para>
/// 支持 ScreenSpaceOverlay / ScreenSpaceCamera / WorldSpace 三种渲染模式。
/// 由外层的 Mask(__Bp_GridBackground)裁剪,确保蓝图节点不溢出视图区域。
/// 缩放范围:0.1x ~ 3x。
/// </para>
/// </summary>
public class ScreenSpaceBlueprintCanvas : BlueprintCanvasBase
{
private readonly UnityEngine.Canvas _unityCanvas;
private readonly RectTransform _renderRoot;
private readonly RectTransform _viewport;
/// <summary>动态获取摄像机引用(不缓存),
/// 自动适应 Canvas.renderMode 运行时的变化。</summary>
private Camera WorldCamera => _unityCanvas != null ? _unityCanvas.worldCamera : null;
/// <summary>
/// 构造屏幕空间蓝图画布
/// </summary>
/// <param name="unityCanvas">所属的 Unity UGUI Canvas 组件</param>
/// <param name="renderRoot">蓝图渲染根 RectTransform,所有蓝图层容器和背景挂载于此</param>
public ScreenSpaceBlueprintCanvas(UnityEngine.Canvas unityCanvas, RectTransform renderRoot, RectTransform viewport = null)
{
_unityCanvas = unityCanvas;
_renderRoot = renderRoot;
_viewport = viewport != null ? viewport : renderRoot;
}
/// <summary>
/// 将屏幕坐标转换为画布坐标。
/// 通过 <see cref="RectTransformUtility.ScreenPointToLocalPointInRectangle"/>
/// 以 <see cref="_renderRoot"/> 为参照转换,
/// 自动处理 Canvas 渲染模式和 RenderRoot 的偏移。
/// </summary>
public override Vector2 ScreenToLocal(Vector2 screenPoint)
{
RectTransformUtility.ScreenPointToLocalPointInRectangle(
_renderRoot, screenPoint, WorldCamera, out Vector2 localPoint);
return localPoint;
}
public override Rect GetViewportLocalRect()
{
if (_viewport == null || _renderRoot == null) return base.GetViewportLocalRect();
var corners = new Vector3[4];
_viewport.GetWorldCorners(corners);
Vector2 min = new Vector2(float.PositiveInfinity, float.PositiveInfinity);
Vector2 max = new Vector2(float.NegativeInfinity, float.NegativeInfinity);
for (int i = 0; i < 4; i++)
{
Vector3 local = _renderRoot.InverseTransformPoint(corners[i]);
min = Vector2.Min(min, local);
max = Vector2.Max(max, local);
}
return Rect.MinMaxRect(min.x, min.y, max.x, max.y);
}
/// <summary>
/// 将画布坐标转换为屏幕坐标。
/// 先计算 RenderRoot 本地空间位置,再通过 RectTransformUtility 转换为屏幕坐标。
/// </summary>
public override Vector2 CanvasToScreen(Vector2 canvasPoint)
{
Vector2 local = canvasPoint * _zoomLevel + _panOffset;
Vector3 world = _renderRoot.TransformPoint(local);
return RectTransformUtility.WorldToScreenPoint(WorldCamera, world);
}
/// <summary>
/// 将画布坐标转换为世界坐标。
/// </summary>
public override Vector3 CanvasToWorld(Vector2 canvasPoint)
{
Vector2 local = canvasPoint * _zoomLevel + _panOffset;
return _renderRoot.TransformPoint(local);
}
/// <summary>
/// 将世界坐标转换为画布坐标。
/// 先转换为屏幕坐标,再通过 RectTransformUtility 转换为 RenderRoot 本地坐标。
/// </summary>
public override Vector2 WorldToCanvas(Vector3 worldPoint)
{
Vector3 screenPoint = RectTransformUtility.WorldToScreenPoint(WorldCamera, worldPoint);
RectTransformUtility.ScreenPointToLocalPointInRectangle(
_renderRoot, screenPoint, WorldCamera, out Vector2 localPoint);
return (localPoint - _panOffset) / _zoomLevel;
}
/// <summary>
/// 获取渲染根 Transform(蓝图层容器和背景的父级)
/// </summary>
public override Transform GetRootTransform()
{
return _renderRoot;
}
/// <summary>
/// 底层 Unity Canvas 引用
/// </summary>
public UnityEngine.Canvas UnityCanvas
{
get { return _unityCanvas; }
}
/// <summary>
/// Canvas 组件未被销毁,画布可正常使用。
/// </summary>
public override bool IsAlive => _unityCanvas != null;
}
}