【Unity】3D UI的焦点设置

3D UI

游戏中经常出现一些斜向放置的UI,这些UI在世界空间中摆放,被透视摄像机所观察。如下图中的设置。

摆放一组带有角度的UI:

 

下图是旋转后的UI,因为使用透视相机的缘故,这里可以看到明显的立体效果。

但我们经常会想控制这些UI的透视,使他们的透视中心不再是屏幕的中心。下图就是将透视中心移动到右上角的效果。

 

实现

上图效果可以类比为,一个普通的透视画面,截取画面左下角的一块图案,而这个图案就是屏幕显示的部分。这里我们可能很快想到通过摄像机的Viewport Rect设置来实现这种效果,但是因为我们希望在UI中使用这个效果,Viewport Rect会影响到很多Canvas相关的设置和屏幕显示位置,使事情变得更加复杂。

于是我们想到另一个办法,改变摄像机的矩阵,正常的相机矩阵如下图所示:

我们可以改变摄像机矩阵,使其不再是一个对称的形体;即近裁面中点、远裁面中点、摄像机位置,三点不再共线。

用以下角度,在正交空间观察:

摄像机位置相对Canva平面的位置就是透视中心,现在透视中心位于正中央,做如下图改变,透视中心变为了右上角,得到了上面那张透视图:

这里可以看到,摄像机矩阵变了,从而透视发生了变化。

我们希望输入屏幕的相对位置,得到一个不会影响Canvas相关设置的结果,但是上图中可以明显看到Canvas(相机正前方的白框)已经与显示内容分离了,其实这里为了不影响UI缩放等逻辑,中间加了一层转换:

Convert便是转换,它使用四周对齐,尺寸与CanvasPlane一致,通过变换位置使其位于变化后的摄像机矩阵中。

代码

注意:下面的计算默认摄像机旋转角度是(0,0,0)。

using UnityEngine;

[ExecuteInEditMode]
public class CameraMatrixSetter : MonoBehaviour
{
    [Header("视觉偏移"), Tooltip("相对屏幕中心的偏移,-1f - 1f的范围是屏幕部分。"), SerializeField]
    private Vector2 offset;
    public Vector2 Offset
    {
        get
        {
            return offset;
        }

        set
        {
            offset = value;
            Refresh();
        }
    }

    public Canvas canvas;
    public Camera worldCamera;
    public Transform convertTransform;

    private void OnEnable()
    {
        Refresh();
    }

    private void OnDisable()
    {
        worldCamera.ResetProjectionMatrix();
        convertTransform.position = new Vector3(0, 0, canvas.planeDistance) + worldCamera.transform.position;
    }

#if UNITY_EDITOR
    private void OnValidate()
    {
        Refresh();
        UnityEditor.SceneView.RepaintAll();
    }

    private void Update()
    {
        Refresh();
    }
#endif

    public void Refresh()
    {
        if (canvas == null || worldCamera == null)
            return;

        Vector2 canvasSize = ((RectTransform)canvas.transform).sizeDelta * canvas.transform.lossyScale;
        Vector2 canvasOffsetSize = -offset * canvasSize;

        Vector2 nearPlaneOffset = canvasOffsetSize * worldCamera.nearClipPlane / canvas.planeDistance;

        worldCamera.ResetProjectionMatrix();
        FrustumPlanes decomposeProjection = worldCamera.projectionMatrix.decomposeProjection;
        decomposeProjection.left += nearPlaneOffset.x;
        decomposeProjection.right += nearPlaneOffset.x;
        decomposeProjection.top += nearPlaneOffset.y;
        decomposeProjection.bottom += nearPlaneOffset.y;
        Matrix4x4 frustumMatrix4x4 = Matrix4x4.Frustum(decomposeProjection);
        worldCamera.projectionMatrix = frustumMatrix4x4;

        UpdateCanvas(canvasOffsetSize);
    }

    private void UpdateCanvas(Vector2 canvasSize)
    {
        if (convertTransform)
        {
            convertTransform.position = new Vector3(canvasSize.x, canvasSize.y, canvas.planeDistance) + worldCamera.transform.position;
        }
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity3D UI主要有四种常用的系统:NGUI、UGUI、OnGUI和Legacy GUI。 NGUI是一款使用最多的第三方UI插件,被广泛应用于国内的游戏界面开发。它提供了丰富的功能和易于使用的界面编辑工具。 UGUIUnity自4.6版本后自带的一套UI系统,逐渐取代了NGUI成为主流。UGUI提供了强大的可视化编辑工具,大大提高了GUI开发效率。 OnGUI主要用于Unity引擎的界面扩展,类似于Web开发中的HTML和CSS的编写方式。它比较底层,需要手动编写代码来创建和控制UI元素。 Legacy GUI是旧版UI系统,只有两个组件:文字和图片,并且使用鼠标事件来实现界面的交互。它非常简单,功能有限。 对于Unity3D UI的创建,可以使用Canvas作为UI组件的父物体。每一个UI组件都必须在Canvas下,并且Unity会自动创建EventSystem来处理输入事件。创建Canvas可以通过在Hierarchy面板中右键点击选择Create -> UI -> Canvas。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Unity3D基础21:UI简介](https://blog.csdn.net/Jaihk662/article/details/86764583)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [unity3DUI](https://blog.csdn.net/m0_57485346/article/details/128011650)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值