Search Unity

Convert from world space coordinate to pixel of render texture

Discussion in 'General Graphics' started by tgaldi, Oct 28, 2015.

  1. tgaldi

    tgaldi

    Joined:
    Oct 28, 2015
    Posts:
    66
    Hey,

    I have a scene with a two camera setup. The main camera is perspective, and displays a UI that includes a panel with a render texture (render texture does not take up the entire UI). The Render Texture is created by another camera, which is orthographic, looking down -y, and provides a god's eye view of the world. I have objects in the world and need to take their world position and translate them into screen space positions of the first camera to use for UI buttons, parented to the render texture panel (so that the button positions match the world positions of the objects within the render texture).

    Currently I've done:

    Vector3 ConvertWorldToScreen( Vector3 positionIn ) {

    RectTransform rectTrans = this.GetComponentInParent<RectTransform>();
    Vector3 screenCoord = orthoCam.WorldToScreenPoint( positionIn );
    Vector3 worldCoord = RectTransformUtility.PixelAdjustPoint( screenCoord, rectTransform.transform, rectTrans.GetComponentInParent<Canvas>() );

    Vector2 offset = rectTrans.offsetMin;
    return new Vector3( offset.x + worldCoord.x, offset.y + worldCoord.y,1f );​
    }

    This seems to work but the points are off a bit. I believe they need to be scaled by the same amount the render texture is scaled across the rectangle panel? Not sure if that is correct or how to perform the scaling.

    Thanks for any assistance.
     
  2. tgaldi

    tgaldi

    Joined:
    Oct 28, 2015
    Posts:
    66
    I've tried scaling by the render texture size:

    Vector3 ConvertWorldToScreen( Vector3 positionIn ) {

    Texture tex = this.GetComponentInParent<RawImage>();
    RectTransform rectTrans = this.GetComponentInParent<RectTransform>();
    Rect rect = rectTrans.rect;

    Vector3 screenCoord = orthoCam.WorldToScreenPoint( positionIn );
    Vector2 scalePoint = new Vector2( ( screenCoord.x * tex.width ) / rec.width, ( screenCoord.y * tex.height ) / rec.height );
    Vector2 offset = rectTrans.offsetMin;
    return new Vector3( offset.x + scalePoint.x, offset.y + scalePoint.y,1f );​
    }

    But the location and scaling of the icons from the correct pixel locations is still off.
     
  3. tgaldi

    tgaldi

    Joined:
    Oct 28, 2015
    Posts:
    66
    I think I'm close:

    Vector3 ConvertWorldToScreen( Vector3 positionIn ) {

    RectTransform rectTrans = this.GetComponentInParent<RectTransform>();

    Vector2 viewPos = orthercam.WorldToViewportPoint( positionIn );
    Vector2 localPos = new Vector2( viewPos.x * rectTrans.sizeDelta.x ), ( viewPos.y * rectTrans.sizeDelta.y ) );
    Vector3 worldPos = rectTrans.TransformPoint( localPos );

    return new Vector3( worldPos.x, worldPos.y, 1f );​
    }

    The positions in relation to each other (local positions) are correct, and they are all in the correct x position in relation to the render texture / rectangle panel (world position). The problem I'm having is that the y positions (world positions) are too high, in that they should be near the bottom of the panel but are at the top and above it.

    I'm kinda flying by the seat of my pants here, so any input is welcome.

    Thanks.
     
    Last edited: Oct 29, 2015
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    7,295
  5. tgaldi

    tgaldi

    Joined:
    Oct 28, 2015
    Posts:
    66
  6. tgaldi

    tgaldi

    Joined:
    Oct 28, 2015
    Posts:
    66
    The solution is to subtract the sizeDelta from the final y coordinate:

    Vector3 ConvertWorldToScreen( Vector3 positionIn ) {

    RectTransform rectTrans = this.GetComponentInParent<RectTransform>();​

    Vector2 viewPos = orthercam.WorldToViewportPoint( positionIn );
    Vector2 localPos = new Vector2( viewPos.x * rectTrans.sizeDelta.x ), ( viewPos.y * rectTrans.sizeDelta.y ) );
    Vector3 worldPos = rectTrans.TransformPoint( localPos );

    return new Vector3( worldPos.x, worldPos.y - rectTrans.sizeDelta.y, 1f );​
    }

    This threw me off because they still will not line up if you don't have maximize on play enabled, or if your screen resolution is different from your canvas rez. I'm assuming the real problem has to do with aspect ratio, but I don't have time to delve any deeper. If someone wants to enlighten me on why this solution works, I'd be interested to know.

    Hope this helps anyone in the future.
     
  7. WarArm

    WarArm

    Joined:
    Dec 4, 2015
    Posts:
    4
    Hello, so this solution doesn't work if you don't habe maximize on play enabled right or if your screen resolution is different from your canvas resolution, right?
     
  8. HiziProjects

    HiziProjects

    Joined:
    Nov 29, 2013
    Posts:
    1
    Good day

    I'm from the future, year 2018. Faced a similar issue, and well.. I wanted it to work with any resolution, and figured a solution that somehow works based on your code.

    I figured I'd share it.

    public Vector3 ConvertWorldToScreen (Vector3 positionIn)
    {
    RectTransform rectTrans = this.GetComponentInParent<RectTransform>(); //RenderTextHolder

    Vector2 viewPos = otherCam.WorldToViewportPoint (positionIn);
    Vector2 localPos = new Vector2 (viewPos.x * rectTrans.sizeDelta.x, viewPos.y * rectTrans.sizeDelta.y);
    Vector3 worldPos = rectTrans.TransformPoint (localPos);
    float scalerRatio = (1 / this.transform.lossyScale.x) * 2; //Implying all x y z are the same for the lossy scale

    return new Vector3 (worldPos.x - rectTrans.sizeDelta.x / scalerRatio, worldPos.y - rectTrans.sizeDelta.y / scalerRatio, 1f);
    }

    Thankies for sharing your code in the first place, and hope that'll save the life of.. somebody
     
    tgaldi likes this.
  9. Farox

    Farox

    Joined:
    Oct 12, 2014
    Posts:
    16
    Thanks!