获取一个 UnityEngine.UI.Image 在屏幕空间中的位置,并计算一个在覆盖画布内的归一化偏移量。

15

问题:

给定一个UnityEngine.Ui.Image,如何找到该图像内标准化偏移量(如从左上角的0.4、0.3)的X、Y位置在屏幕空间单位(如400、300)内?

我想我需要找到左上角的屏幕空间值,然后根据以像素表示的实际大小比例缩放规范化偏移量。

图1: Figure 1:

图2 显示了要使用的 normalizedOffsets

图2: An example stored Rect "offset"

因此,简言之,我需要找到已存储在图像中的矩形的左上角在屏幕空间像素中的偏移量。

我认识到这可能是 Camera.main.ViewportToWorldPoint() 的组合和一些参考边界,可能将其按 backgroundImage.sprite.pixelsPerUnit 缩放?

我很难想象如何确切地完成这项工作。

谢谢


1
你是否在寻找TransformPoint() - Draco18s no longer trusts SE
2
看了你发布的代码,它永远不会工作,因为你正在取一个转换后的点并加/减未转换的值。此外,ViewportToWorld没有考虑到世界空间中的画布:仅仅因为相机的中心在(x,y,z)处,并不意味着画布的中心也在(x,y,z)处(毕竟,它是在世界空间中具有自己独立于相机的坐标系)。然而,这个旧答案可能会有所帮助。 - Draco18s no longer trusts SE
2
简化版:(0.4, 0.3) 是什么意思?这些单位是什么?在哪个空间中?世界空间?如何考虑屏幕纵横比?视野?相机旋转?您的图像似乎表明您希望在面部(或其他特征)周围画一个正方形,但该特征存在于像素空间中:您必须将那些单位转换为世界空间单位,而不是反过来。 - Draco18s no longer trusts SE
2
获取 rect transform 的宽度,乘以你的 (0.4, 0.3) 值,加上左上角,转换为世界空间。 - Draco18s no longer trusts SE
2
如果您想在任何摄像机角度下使用它,我认为这并不像“知道图像的渲染总大小”那么简单。我会使用您的图像所在的3D平面方程式来处理,然后计算该平面上的偏移量,最后使用相机的视图和投影矩阵将该结果转换为屏幕坐标。希望这可以帮到您。 - Jinjinov
显示剩余11条评论
1个回答

0

我猜你的图像父级中没有任何比例或旋转,并且位置Y为0。

首先,您可以使用 rectTransform.GetWorldCorners()获取图像左上角的位置:

    //Upper left corner
    Vector3[] v = new Vector3[4];
    image.rectTransform.GetWorldCorners(v);
    var recPos = v[1];

然后,您需要通过图像大小和矩形大小之间的比率将规范化偏移转换为世界空间偏移,并添加左上角位置的位置:

    var recWidth = image.rectTransform.sizeDelta.x;
    var imgWidth = image.sprite.texture.width;
    var realOffsetX = offsetX * (recWidth / imgWidth);
    var realPosX = recPos.x + realOffsetX;

对于 Y 坐标,使用相同的公式,但是您必须减去您的比率 realOffsetY,因为偏移量是从左上角计算的。

以下是完整的方法:

private Vector3 GetPositionOffset(Image image, float offsetX, float offsetY)
{
    //Upper left corner
    Vector3[] v = new Vector3[4];
    image.rectTransform.GetWorldCorners(v);
    var recPos = v[1];

    //X coordinate
    var recWidth = image.rectTransform.sizeDelta.x;
    var imgWidth = image.sprite.texture.width;
    var realOffsetX = offsetX * (recWidth / imgWidth);
    var realPosX = recPos.x + realOffsetX;

    //Y coordinate
    var recHeight = image.rectTransform.sizeDelta.y;
    var imgHeight = image.sprite.texture.height;
    var realOffsetY = offsetY * (recWidth / imgWidth);
    var realPosY = recPos.y - realOffsetY;

    //Position
    return new Vector3(realPosX, realPosY, image.transform.position.z);
}

如果您想将此世界空间转换为屏幕空间,只需使用相机方法:

camera.WorldToScreenPoint(positionOffset);

让我检查一下。感谢您的帮助。 - twobob
如果我将0,0作为我的偏移量传入, 然后运行 Camera.Main.WorldToScreenPoint(positionOffset); 我没有得到预期的默认输出,即左上角?我一定漏掉了什么。 - twobob
实际上,结果位置偏离屏幕相当远,你有一个经过测试的工作样例吗? - twobob
@twobob 这很奇怪,如果你传递0,0,那么位置应该来自GetWorldCorners(),并且它必须是图像左上角的位置。您的父对象是否有任何缩放/旋转? - Ludovic Feltz
我在Visual Studio中逐行跟踪了数学计算,但不清楚哪里可能出错了。 - twobob
我没有缩放或旋转。 我的第一个值为46,766。 你有一个实例吗? - twobob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接