Raycast获取平面击中位置的本地坐标

3

我有一个比例为(64,1,36)的平面,旋转角度为(90,-180,0),需要将射线碰撞点的本地坐标转换成2D坐标格式:

(0,0)-------(64,0)
 |             |
 |             |
 |             |
(0,36)------(64,36)

使用我的当前代码:

RaycastHit hit;
Vector3 coords = new Vector3();
if (Physics.Raycast(GazeOriginCombinedLocal, GazeDirectionCombined, out hit, Mathf.Infinity))
    {
        if (!hit.transform.Equals("Cube"))
        {
            Pointer.transform.position = hit.point; //Green cube for visualization of hit in worldspace
            // coords = RectTransformUtility.ScreenPointToLocalPointInRectangle(Plane, hit.point, Camera.main, out coords);// no result at all
        }

       
    }

尝试这样做:

hit.transform.InverseTransformPoint(hit.point)

给我这个

(5,-5)---(-5,-5)
  |         |
  |  (0,0)  |
  |         |
(5,5)----(-5,5)

有没有想法获取所需的格式?

这是我的平面,它是主摄像机的子物体,以下是我的层级结构: 图片描述 图片描述 图片描述 提前感谢。


请编辑问题并包含一个 [mre]。这应该包括所有相关游戏对象的层次结构以及任何附加的碰撞器或其他组件。 - Ruzihm
请包括 Camera 游戏对象的变换(特别是显示比例)。 - Ruzihm
相机的比例为(1,1,1)。我已经添加了一张照片,所以我没有找到解决方案,因为这些数字似乎如此随意。 - Hagi
2个回答

2
我认为你可以使用 Transform.InverseTransformPoint,它将位置从世界空间转换为本地空间。然后,由于这也受比例的影响,再次使用 Vector3.Scale 乘以平面的比例。因此,你的坐标应该是类似这样的:
coords = hit.transform.localScale / 2f +  Vector3.Scale(hit.transform.InverseTransformPoint(hit.point), hit.transform.localScale);

目前无法测试,因为在智能手机上打字。根据您的需求和平面的旋转等情况,您可能需要反转y / z分量。但我希望这能给您一个想法。
为了调试出问题的原因,您应该逐步打印出值。
var scale = hit.transform.localScale; // 64, 1, 36
var halfScale = scale / 2f; // 32, 0.5, 18

var localHitPoint = hit.transform.InverseTransformPoint(hit.point);
Debug.Log($"{nameof(localHitPoint)}:{localHitPoint:0.000}");

所以我最初期望的是这里的值会像这样。
(-0.5, 0.5, 0)----(0.5, 0.5, 0)
       |                |
       |   (0, 0, 0)    |
       |                |
(-0.5, -0.5, 0)---(0.5, -0.5, 0)

但是,正如你现在所添加的:“你的飞机被旋转了!”
在X轴上的90°实际上使Y轴和Z轴交换位置。因此,为了得到所需的Y坐标,你应该读取localHitPoint.z
然后,在Y轴上的180°基本上颠倒了X轴和Z轴。
因此,我现在希望值看起来像:
(0.5, 0, -0.5)----(-0.5, 0, -0.5)
       |                |
       |   (0, 0, 0)    |
       |                |
(0.5, 0, 0.5)---(-0.5, 0, 0.5)

这段话的意思是:“这看起来非常像您描述的值。但不确定为什么要乘以10,也不知道为什么不需要交换Y和Z。然而,由于您实际上想让0,0位于左上角,所以您只需要翻转X轴并使用Z代替Y。”
fixedLocalHitPoint = new Vector2(-localHitPoint.x, localHitPoint.z);
Debug.Log($"{nameof(fixedLocalHitPoint)}:{fixedLocalHitPoint:0.000}");

现在应该给你提供像这样的值
(-0.5, -0.5)----(0.5, -0.5)
       |             |
       |   (0, 0)    |
       |             |
 (-0.5, 0.5)----(0.5, 0.5)

仍然需要再次扩大规模。
var scaledHitPoint = Vector2.Scale(fixedLocalHitPoint, new Vector2 (scale.x, scale.z));
Debug.Log($"{nameof(scaledHitPoint)}:{scaledHitPoint:0.000}");

现在应该给出类似于以下的值
(-32, -18)----(32, -18)
     |             |
     |   (0, 0)    |
     |             |
 (-32, 18)-----(32, 18)

这就是为什么你需要将中心点作为参考点添加的原因。
coords =  new Vector2(halfScale.x, halfScale.z) + scaledHitPoint;
Debug.Log($"{nameof(coords)}:{coords:0.000}");

这现在应该是什么。
(0, 0)------(64, 0)
   |            |
   |  (32, 18)  |
   |            |
(0, 36)-----(64, 36)

我希望这能让你更加了解这些“奇怪”的值来自哪里。
由于你的相机缩放比例为1,1,1,且没有其他因素参与计算,说实话我很难找到这个因数10是从哪里悄悄溜进计算中的。

我已经编辑了我的帖子,并附上了您的代码结果,因为它没有按预期工作。该平面没有RectTransform,因此枢轴在中间,但InverseTransformPoint的结果非常奇怪。 - Hagi
我更新了使用本地比例而不是全局比例..听起来你的飞机有一些父级对象的缩放不同?你能再检查一下吗?顺便说一句,你接受了另一个答案,基本上拿走了我已经投入思考的所有东西,并且只是用一些硬编码乘数进行了热修复值.... - derHugo
父级(即主相机)未被缩放且位于原始位置,因此使用lossyscale=localscale会导致不幸的错误结果。 - Hagi
@Dadium 我在底部添加了一些进一步的想法,也许可以帮助你理解为什么会得到奇怪的值。其中一个主要原因是你的平面本地旋转导致轴被翻转..我仍在努力找出为什么你的值偏差了10倍... - derHugo
非常酷,这真的帮了我很多,非常感谢。当我说到奇怪的值时,我指的是和你遇到问题相同的事情。在场景中,除了将平面附加到相机以始终面向用户之外,没有其他更多的东西。然而,这解决了我的问题,所以也许我以后会找到原因,但现在我很高兴。 - Hagi

2
如果您想将此转换为:
hit.transform.InverseTransformPoint(hit.point)

这将会得到这样的结果:
(5,-5)---(-5,-5)
  |         |
  |  (0,0)  |
  |         |
(5,5)----(-5,5)

转换为:

(0,0)-------(64,0)
 |             |
 |             |
 |             |
(0,36)------(64,36)

为什么不这样做:
Vector2.Scale(
        hit.transform.InverseTransformPoint(hit.point) - new Vector2(5,-5),
        new Vector2(-6.4, 3.6) 
        );

这个答案将(5,-5)(-6.4,3.6)这些术语硬编码了进去,因为问题中没有包含足够的信息来使用变量。

假设飞机父级(Main Camera)的比例为(10,10),那么这应该就足够了:

Vector3 planeScale = hit.transform.localScale;
Vector3 cameraScale = hit.transform.parent.localScale;

result = Vector2.Scale(
          hit.transform.InverseTransformPoint(hit.point) 
        - new Vector2(cameraScale * 0.5f ,-cameraScale * 0.5f),
        new Vector2(-planeScale.x * 0.5f/cameraScale.x, planeScale.y * 0.5f / cameraScale.y) 
        );

(-6.4,0, 3.6) 是关键... lossyscale(64,1,36)给出了错误的结果,谢谢。 - Hagi
1
听起来像是一个热修复..如果你仔细看,你会发现这些值基本上是lossyScale,但x被倒置并除以10..听起来像是某个父级别的缩放不同,你应该更好地使用localScale..我在我的答案中改变了这个..对我来说,接受一个基本上完全基于我已经思考过很多的东西的答案,并用一些硬编码的乘数进行热修复,听起来有点不公平...;) 不是我不喜欢你Ruzihm :D - derHugo
我同意,如果你认为我的回答有帮助,请点赞,但请不要接受它。如果你认为这更公平,我可以删除这个答案@derHugo。在你建议之后,我没有看到提问者只放了“尝试这个:”部分。 - Ruzihm

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