Search Unity

Camera.WorldToScreenPoint Offsets Vertically with Orthographic Camera

Discussion in '2D' started by RedVonix, Jan 30, 2021.

  1. RedVonix

    RedVonix

    Joined:
    Dec 13, 2011
    Posts:
    422
    I'm attempting to grab a texture of a single object on the screen to replace that object with a plane that has the texture applied. I've written code that will grab the object with a RenderTexture, however the resulting image is always offset vertically. The issue appears to be with WorldToScreenPoint giving strange results. I've attempted a number of fixes including ensuring everything has the same Z coordinate, but no luck. I'm also drawing a box around the object in WorldSpace coordinates to be certain the positions are accurate.

    Here is what the camera sees.
    upload_2021-1-30_16-27-10.png

    And here is what the final texture looks like. It should match the square surrounding the object.
    upload_2021-1-30_16-27-41.png

    Here is my code:
    Code (CSharp):
    1.     private IEnumerator RenderTarget()
    2.     {
    3.         Bounds worldBounds = spineSkeletonAnimToRender.GetComponent<MeshRenderer>().bounds;
    4.  
    5.         Vector3 worldBottomLeft = new Vector3(worldBounds.min.x, worldBounds.min.y, 0f);
    6.         Vector3 worldTopLeft = new Vector3(worldBounds.min.x, worldBounds.max.y, 0f);
    7.         Vector3 worldTopRight = new Vector3(worldBounds.max.x, worldBounds.max.y, 0f);
    8.         Vector3 worldBottomRight = new Vector3(worldBounds.max.x, worldBounds.min.y, 0f);
    9.  
    10.        // Draw a box around the target object for debugging.
    11.         Debug.DrawLine(worldBottomLeft, worldTopLeft, Color.blue, 10f);
    12.         Debug.DrawLine(worldTopLeft, worldTopRight, Color.red, 10f);
    13.         Debug.DrawLine(worldTopRight, worldBottomRight, Color.green, 10f);
    14.         Debug.DrawLine(worldBottomRight, worldBottomLeft, Color.yellow, 10f);
    15.  
    16.         Vector2 screenTopRight = shatterRenderCamera.WorldToScreenPoint(worldTopRight);
    17.         Vector2 screenBottomRight = shatterRenderCamera.WorldToScreenPoint(worldBottomRight);
    18.         Vector2 screenBottomLeft = shatterRenderCamera.WorldToScreenPoint(worldBottomLeft);
    19.        
    20.         shatterRenderCamera.targetTexture = new RenderTexture(Screen.width, Screen.height, 32);
    21.        
    22.         // First render....
    23.         shatterRenderCamera.Render();
    24.         yield return frameEnd;
    25.  
    26.         // After rendering, set that texture as the active render texture, and grab the pixels
    27.         RenderTexture.active = shatterRenderCamera.targetTexture;
    28.  
    29.             Texture2D finalTexture = new Texture2D(Mathf.RoundToInt(screenBottomRight.x - screenBottomLeft.x), Mathf.RoundToInt(screenTopRight.y - screenBottomRight.y), TextureFormat.RGBA32, false);
    30.             finalTexture.ReadPixels(new Rect(screenBottomLeft.x, screenBottomLeft.y, screenBottomRight.x - screenBottomLeft.x, screenTopRight.y - screenBottomRight.y), 0, 0, false);
    31.             finalTexture.Apply();
    32.  
    33.             renderedTexture = finalTexture;
    34.         RenderTexture.active = null;
    35.         shatterRenderCamera.targetTexture = null;
    36.     }
    37.  
    38.     public Rect GetCurrentRectBoundsForSkeleton()
    39.     {
    40.         float[] vertexBuffer = null;
    41.         spineSkeletonAnimToRender.skeleton.GetBounds(out float boundsX, out float boundsY, out float boundsWidth, out float boundsHeight, ref vertexBuffer);
    42.  
    43.         return new Rect(boundsX + transform.position.x, boundsY + transform.position.y, boundsWidth, boundsHeight);
    44.     }
    I'm pretty baffled at this point as to why it is offset and could use some advice. Thanks in advance!
     
  2. RedVonix

    RedVonix

    Joined:
    Dec 13, 2011
    Posts:
    422
    Got this resolved thanks to xEvilReeperx from the Unity Discord. I had some values inverted. The fix is as such:

    Code (CSharp):
    1. var width = Mathf.RoundToInt(screenBottomRight.x - screenBottomLeft.x);
    2. var height = Mathf.RoundToInt(screenTopRight.y - screenBottomRight.y);
    3. var srcx = screenBottomLeft.x;
    4. var srcy = Screen.height - screenTopRight.y;
    5. Texture2D finalTexture = new Texture2D(width, height, TextureFormat.RGBA32, false);
    6. finalTexture.ReadPixels(new Rect(srcx, srcy, width, height), 0, 0, false);