如何将新画布UI图像位置转换为线性渲染器位置?

3

我在画布中使用了屏幕空间-相机渲染模式的图像UI。我想要做的是通过循环遍历所有LineRenderer位置并更改其y轴来将我的LineRenderer移动到图像垂直位置。我的问题是我无法获得LineRenderer可以理解的图像正确位置。我尝试使用ViewportToWorldPointScreenToWorldPoint,但它们的位置不同。

    Vector3 val = Camera.main.ViewportToWorldPoint(new Vector3(image.transform.position.x, image.transform.position.y, Camera.main.nearClipPlane));

    for (int i = 0; i < newListOfPoints.Count; i++)
    {
        line.SetPosition(i, new Vector3(newListOfPoints[i].x, val.y, newListOfPoints[i].z));
    }

使用 Vector3 val = Camera.main.ScreenToWorldPoint(new Vector3(image.transform.localPosition.x, image.transform.localPosition.y, -10)); 可以截取屏幕结果。

绿色的LineRenderer是通过改变y坐标得到的。它应该位于正方形图像的底部。 enter image description here


1
你能添加一张当前代码渲染的截图吗?在屏幕空间和世界空间之间匹配物体是很棘手的事情,看到正在发生的事情会有所帮助。 - Draco18s no longer trusts SE
打印出图像的屏幕空间位置怎么样?也许它不在你认为它应该在的位置上。另一个尝试的方法可能是看看(0,0)或(100,100)被转换成什么。 - YAC
1
@YAC 真正的问题在于叠加画布对象使用完全不同的坐标系,与世界空间和视口空间不同。 - Draco18s no longer trusts SE
@unice,如果您的问题已经解决,请接受答案,这样对其他人也会有帮助。 - Programmer
1
@程序员,抱歉回复晚了。我一直在测试脚本,在Canvas中使用屏幕空间-叠加渲染模式时,它完美地工作。但是当我使用屏幕空间-摄像机并将我的主摄像机拖到渲染摄像机时,线渲染器的位置会有所不同。但这已足以回答我的问题,我现在会坚持使用叠加模式。感谢 Draco18s 抽出时间和精力来回答我的问题 :) - unice
1个回答

3

哇,这真的很烦人和复杂。

这是我最终得出的代码。你问题中的代码是 Update() 函数的下半部分。我唯一改变的是传递给 ScreenToWorldPoint() 方法的值。该值在 Update() 函数的上半部分中计算。

RectTransformToScreenSpace() 函数修改自 this Unity Answer 文章1,关于获取 RectTransform 的屏幕空间坐标(这正是我们想要的,以便将屏幕空间坐标转换回世界空间!)。唯一的区别是我获得了反转的 Y 值,所以我从 Screen.height - transform.position.y 改为了 transform.position.y,完美解决了问题。

之后的事情就只是抓住那个矩形的左下角,将其从Vector2更改为Vector3,并将其传回ScreenToWorldPoint()。唯一的技巧在于透视相机,我需要知道线条最初距离相机有多远才能保持相同的距离(否则线条移动速度比图像快)。对于正交相机,此值可以是任何值。

void Update () {
    //the new bits:
    float dist = (Camera.main.transform.position - newListOfPoints[0]).magnitude;
    Rect r = RectTransformToScreenSpace((RectTransform)image.transform);
    Vector3 v3 = new Vector3(r.xMin, r.yMin, dist);

    //more or less original code:
    Vector3 val = Camera.main.ScreenToWorldPoint(v3);
    for(int i = 0; i < newListOfPoints.Count; i++) {
        line.SetPosition(i, new Vector3(newListOfPoints[i].x, val.y, newListOfPoints[i].z));
    }
}

//helper function:
public static Rect RectTransformToScreenSpace(RectTransform transform) {
    Vector2 size = Vector2.Scale(transform.rect.size, transform.lossyScale);
    Rect rect = new Rect(transform.position.x, transform.position.y, size.x, size.y);
    rect.x -= (transform.pivot.x * size.x);
    rect.y -= ((1.0f - transform.pivot.y) * size.y);
    return rect;
}

1在一般搜索“如何获取UI对象的屏幕坐标”时,找到那篇文章并不容易。出现了许多其他帖子并且有一些代码,但是没有一个能够满足我的要求(包括将屏幕空间坐标转换回UI对象的世界空间坐标,这很愚蠢且不能逆转,感谢RectTransformUtility!)


我一直在寻找将UI转换为世界空间的方法,但没有时间设置场景来测试它。这真的有效吗? - Programmer
2
@程序员 在回答之前,我在Unity中测试了所有这些代码。它是有效的。 :) 但我没有设置录制任何视频的设备。我使用的整个类img 1img 2(我没有正确设置线渲染器)。左边缘与图像居中对齐,仅因为线渲染器上的第一个点位于X = 0处(相机在X轴上居中),并且图像也居中于屏幕。提问者的代码只关心Y位置。 - Draco18s no longer trusts SE
好的,我稍后会用不同的相机和画布模式设置来测试它。我认为你还应该将其作为一个Vector3函数,将UI空间转换为世界空间。我看到许多关于这个主题被忽略的问题,需要将UI转换为世界位置。我想使用这个重复的答案来关闭其他旧的和未来的问题。 - Programmer
2
@程序员 这个函数将仅返回 rect.center - Draco18s no longer trusts SE

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