liquid.pizza
liquid.pizza

Reputation: 525

World to screen coordinates in Unity

For my current project it is necessary, that I compute the screen coordinates of a given point in the world space in Unity.

I used this tutorial to write a methode to do so.

After some debugging the x and y screen coordinate are correct, but my z coordinates looks wrong and I have some more questions:

static public Vector3 convertWorldToScreenCoordinates (Vector3 point, PhotoData photoData)
{   
    // get the camera
    Camera camera = GameObject.Find (photoData.cameraName).camera;

    /*
    * 1 convert P_world to P_camera
    */
    Vector4 pointInCameraCoodinates = convertWorldToCameraCoordinates (point, photoData);


    /*
    * 2 convert P_camera to P_clipped
    */
    Vector4 pointInClipCoordinates = camera.projectionMatrix * pointInCameraCoodinates;

    /*
    * 3 convert P_clipped to P_ndc 
    * Normalized Device Coordinates
    */
    Vector3 pointInNdc = pointInClipCoordinates / pointInClipCoordinates.w;


    /*
    * 4 convert P_ndc to P_screen
    */
    Vector3 pointInScreenCoordinates;
    pointInScreenCoordinates.x = camera.pixelWidth / 2.0f * (pointInNdc.x + 1);
    pointInScreenCoordinates.y = camera.pixelHeight / 2.0f * (pointInNdc.y + 1);
    pointInScreenCoordinates.z = ((camera.farClipPlane - camera.nearClipPlane) * pointInNdc.z + (camera.farClipPlane + camera.nearClipPlane)) / 2.0f;


    // return screencoordinates
    return pointInScreenCoordinates;        
}

PhotoData is a class, that contains some information about the camera. The important part here is that I can access the camera.

static public Vector4 convertWorldToCameraCoordinates (Vector3 point, PhotoData photoData)
{
    // translate the point by the negative camera-offset 
    //and convert to Vector4
    Vector4 translatedPoint = point - photoData.cameraPosition;
    // by default translatedPoint.w is 0
    translatedPoint.w = 1.0f;

    // create transformation matrix
    Matrix4x4 transformationMatrix = Matrix4x4.identity;

    transformationMatrix.SetRow (0, photoData.camRight);
    transformationMatrix.SetRow (1, photoData.camUp);
    transformationMatrix.SetRow (2, - photoData.camForward);            

    Vector4 transformedPoint = transformationMatrix * translatedPoint;

    return transformedPoint;
}

First of all, the tutorial mentions, that after computing the ndc-values, "the range of values is now normalized from -1 to 1 in all 3 axes". This is not true in my case and I do not see what I am doing wrong.

My second question is, does pointInClipCoordinates.z < 0 mean the world point is "behind" my camera?

And the last question so far is why do I have to use - photoData.camForward?

// edit: updated code + questions

Upvotes: 1

Views: 3400

Answers (1)

zwcloud
zwcloud

Reputation: 4889

For editor scripts, use HandleUtility.WorldToGUIPoint (available since Unity3D 4.12) to convert a world space point to a 2D GUI position.

Upvotes: 1

Related Questions