Unity编辑器拓展——Editor模式下屏幕坐标转换为世界坐标

发会牢骚,最近一直在做Unity的编辑器拓展,其中难的地方不少,但不至于到看不懂的地步,可一做到关于坐标转换的内容时把我弄不会了。

这个不查不知道,一查吓一跳,Unity的坐标系非常多,有世界坐标,屏幕坐标,局部坐标,视窗坐标等等,而且每一个都是不一样的坐标系,所以关于Unity的坐标变换都挺麻烦的,但其实也不是难题,有很多现成的答案,前提是不在Editor模式下操作。

淦就淦在我就是要做编辑器拓展,所以就遇到了几乎一片空白的领域。不是没有相关的文章,关于编辑器拓展下的坐标系转换是有文章的,但在我的情况下全都不对,我就纳闷了,甚至想要直接写函数去实现,不过在磨了一天一夜后在机缘巧合下给我看出了问题。


目录

描述问题

问题所在

解决办法


描述问题

我做的是2D游戏,在编辑模式下的一个拓展窗口内需要为一个数据选定场景坐标,我首先想到的是通过鼠标位置转换成世界坐标来实现。有各种各样的问题,不过大都可以在百度上找到答案,只是关键的坐标转换却出了问题,我死活都拿不到想要的数据。

问题所在

(随便找的图)

P1:我需要转换的P2物体内的坐标位置,即鼠标点击的位置

P2:某物体的位置点

P3:场景窗口的左上角的位置

P4:场景窗口的左下角的位置

获取P1坐标的代码如下

    private void OnSceneView(SceneView sceneView)
    {
        //鼠标左键点击判断
        if (Event.current.type == EventType.MouseDown && Event.current.button == 0)
        {
                Vector2 newPosition;

                //P2指P1所需要转换的位置的父物体
                Transform P2 = GameObject.Find("P2").transform;     
                
                //坐标转换
                RectTransformUtility.ScreenPointToLocalPointInRectangle(P2.GetComponent<RectTransform>(), GetMousePos(), sceneView.camera, out newPosition);
                
                Debug.Log(newPosition);
            }
        }
    }

Input类没法在编辑模式下用,所以用场景事件类,而RectTransformUtility.ScreenPointToLocalPointInRectangle这个方法就不多介绍了,简单来说就将屏幕坐标转换为某个物体内的坐标,挺人性的,就是没摸透时用有点折磨。RectTransformUtility类还有其他转换方法,百度上挺多答案的。

一开始我用Event.current.mousePosition来获取鼠标位置,我想将P1从屏幕坐标转换为世界坐标,用的是Camera自带的转换函数,是错的。因为P1的坐标不是正确的数据,不是准确的屏幕坐标。

常用的坐标系有这几个

而P1的坐标是GUI坐标系的,不能直接拿来转换。Event.current.mousePosition获取的鼠标坐标是GUI坐标,需要先将其转换为Screen的坐标系,转换为屏幕坐标才能用。

也就是P3是GUI坐标系的原点,而P4是屏幕坐标系的原点,P1在P3的坐标系下,P2在世界坐标系下,总之在这乱成一锅粥的坐标系下进行转换。

解决办法

    public static Vector3 GetMousePos()
    {
        SceneView sceneView = SceneView.currentDrawingSceneView;

        //当前屏幕坐标,左上角(0,0)右下角(camera.pixelWidth,camera.pixelHeight)
        Vector2 mousePos = Event.current.mousePosition;

        //retina 屏幕需要拉伸值
        float mult = 1;

#if UNITY_5_4_OR_NEWER
        mult = EditorGUIUtility.pixelsPerPoint;

#endif
        //转换成摄像机可接受的屏幕坐标,左下角是(0,0,0);右上角是
        (camera.pixelWidth,camera.pixelHeight,0)
        mousePos.y = sceneView.camera.pixelHeight - mousePos.y * mult;
        mousePos.x *= mult;

        //近平面往里一些,才能看到摄像机里的位置
        Vector3 fakePoint = mousePos;
        fakePoint.z = 10;
        return fakePoint;
    }

这个函数返回的就是准确的屏幕坐标,将GUI坐标系的坐标转换为Screen坐标系下的,我是直接拿网上的代码改了一下,因为是2D项目,所以应该和Z轴没关系,当然也不能设置在相机背面,这点就不说了。

上面的代码出处:Unity获取Scene窗口下的鼠标位置的世界坐标_BRK小布的博客-CSDN博客_unity 获取窗口位置

源码直接转成世界坐标,我想用Camera的转换函数也行,看情况吧,源码没法转换成某个物体内的坐标系。

总结

淦他娘的Unity,坐标转换弄死人了,不过弄懂了这块内容基本上以后遇到类似问题就大致有数了。

首先弄清楚获取的坐标到底是在哪个坐标系下的,然后再转换到对应的坐标系就行了。对了,有部分原因是因为用的Camera弄错了,我的项目里有两个Camera,但都是错的,这其实也应该是一个坑,而且还没搞懂,弄了好久,测这测那的,最后是换成了sceneView.camera才拿到了正确的数据,难道还有隐藏的摄像机,不太清楚,如果是用的OnSceneView(SceneView sceneView)事件函数,直接用sceneView.camera这个摄像机就行了,大概(⊙_⊙)。

最后,能帮到你就大概达到了写这个文章的目的,祝各位好运。

猜你喜欢

转载自blog.csdn.net/weixin_49779414/article/details/127380072
今日推荐