首页 > 解决方案 > Unity WorldToViewPortPoint not giving correct y position

问题描述

I have a script that places an UI element on the place where a 3d object is in 3d space. I do this in the following way:

public class test : MonoBehaviour {

public Camera MainC;
public GameObject testc;

// Use this for initialization
void Start () {
    var ui = Object.Instantiate((GameObject)Resources.Load("uit"), Vector2.zero, Quaternion.identity);
    ui.transform.SetParent(GameObject.FindObjectOfType<Canvas>().gameObject.transform, false);

    var vertexs = testc.GetComponent<MeshFilter>().mesh.vertices;
    var trs = testc.GetComponent<Transform>();
    var cdc = new Vector2(GameObject.FindObjectOfType<Canvas>().GetComponent<RectTransform>().sizeDelta.x , GameObject.FindObjectOfType<Canvas>().GetComponent<RectTransform>().sizeDelta.y); 

    Object.Instantiate((GameObject)Resources.Load("pinksphere"), trs.transform.TransformPoint(vertexs[6]), Quaternion.identity); //bottomright
    Object.Instantiate((GameObject)Resources.Load("pinksphere"), trs.transform.TransformPoint(vertexs[5]), Quaternion.identity); //topleft

    var tl = MainC.WorldToViewportPoint(trs.transform.TransformPoint(vertexs[5]));

    var topleft = new Vector2(tl.x * cdc.x, tl.y * -(cdc.y) );
    ui.GetComponent<RectTransform>().anchoredPosition = topleft;
}

}

But this does not place the UI Element on the desired position. See the following images for more explaination.

enter image description here

in this case i want the TOPLEFT corner of the UI element to be ontop of the pink dot at the TOPLEFT of the whitecube. But as you can see the Y-axis doesnt quite match..

Some extra information about the conditions like canvas used and the prefab settings. See images below:

enter image description here these are the canvas settings.

enter image description here this are the Main Camera settings.

enter image description here and this are the UI prefab settings.

If you need any more information or something isnt clear let me know so i can clarify!
the code is really inefficient and ugly but it is only for testing purposes :)

标签: c#user-interfaceunity3dcanvasmapping

解决方案


A minimal edit to your code that gets the desired effect:

public class Test : MonoBehaviour
{

    public Camera MainC;
    public GameObject testc;

    // Use this for initialization
    void Start()
    {
        var ui = Object.Instantiate((GameObject)Resources.Load("uit"), Vector2.zero, Quaternion.identity);
        ui.transform.SetParent(GameObject.FindObjectOfType<Canvas>().gameObject.transform, false);
        var uiRT = ui.GetComponent<RectTransform>();
        // Ensure uiRT's pivot and anchors are set to the bottom left preset.
        uiRT.anchorMin = Vector2.zero;
        uiRT.anchorMax = Vector2.zero;
        uiRT.pivot = Vector2.zero;

        var vertexs = testc.GetComponent<MeshFilter>().mesh.vertices;
        var trs = testc.GetComponent<Transform>();
        var cdc = new Vector2(GameObject.FindObjectOfType<Canvas>().GetComponent<RectTransform>().sizeDelta.x, GameObject.FindObjectOfType<Canvas>().GetComponent<RectTransform>().sizeDelta.y);

        Object.Instantiate((GameObject)Resources.Load("pinksphere"), trs.transform.TransformPoint(vertexs[6]), Quaternion.identity); //bottomright
        Object.Instantiate((GameObject)Resources.Load("pinksphere"), trs.transform.TransformPoint(vertexs[5]), Quaternion.identity); //topleft

        var tl = MainC.WorldToViewportPoint(trs.transform.TransformPoint(vertexs[5]));

        var offset = new Vector2(0, uiRT.sizeDelta.y);
        var topleft = tl * cdc - offset;
        uiRT.anchoredPosition = topleft;
    }
}

Your UI image's pivot and anchors must be set to Bottom Left for this to work:

UI Image pivot and anchors set to bottom left

I've added code that will ensure the pivot and anchors are set this way. You may remove it as long as you ensure the prefabs have the bottom left preset, but it's safer this way.

The reasoning for doing it this way is the following:

Viewport coordinates have the 0,0 origin point in the bottom left, so if you set the pivot and anchors there it all lines up and you don't need to do any translation of coordinates - it just saves a lot of headache. The only thing that's left is to subtract the height of the UI Image in order to get it to line up vertically with the 3D cube.


推荐阅读