Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

converting 3d position to 2d screen position

Tags:

c++

math

2d

3d

I'd like to convert a 3d position into 2d screen position. I had a look at a similar question: Projecting a 3D point to a 2D screen coordinate , but I dont understand it completely. I thought in order to calculate the 2d position I would need the projection matrix, but I dont see how it is used, apart from converting a point into the location coordinate space. Besides, is cam.FieldOfView equal to farZ in OpenGL?

Could someone please help me complete this function. Are the parameters sufficient to calculate the 2d position? Pos is already a vector relative to the camera position.

       Vector2* convert(Vector3& pos, Matrix4& projectionMatrix, int screenWidth, int screenHeight)
       {
            float ratio = screenWidth / screenHeight; 

            ...

            screenX = screenWidth * ( 1.0f - screenX); 
            screenY = screenHeight * ( 1.0f - screenY);    

            return new Vector2(screenX, screenY); 
       }
like image 378
Pedro Avatar asked Dec 02 '22 01:12

Pedro


2 Answers

Seems to me it would be something like that:

    Vector2 Convert(Vector3 pos, const Matrix& viewMatrix, const Matrix& projectionMatrix, int screenWidth, int screenHeight)
    {
        pos = Vector3::Transform(pos, viewMatrix);
        pos = Vector3::Transform(pos, projectionMatrix);

        pos.X = screenWidth*(pos.X + 1.0)/2.0;
        pos.Y = screenHeight * (1.0 - ((pos.Y + 1.0) / 2.0));

        return Vector2(pos.X, pos.Y);
    }

What are we doing here is just passing the Vector though the two transformation matrices: the view, then the projection. After the projection you get a vector with Y and X between -1 and 1. We do the appropriate transformation to obtain real pixel coordinates and return a new Vector2. Note that the Z component of 'pos' also store the depth of the point, in the screen space, at the end of the function.

You need the 'view' matrix because it defines where the camera is located and rotated. The projection only defines the way the 3D space is 'flattened' on the 2D space.

A field of view is not the farZ. A projection matrix has some parameters, among them:

  • the field of view, FOV, that is the horizontal angle of view, in radians;
  • the far plane, or farZ : this defines the maximum distance a point can be from the camera;
  • the near plane, nearZ: the minimum distance a point can be from the camera.

Besides the math problem, you may use directly the Vector2 instead of a heap allocation (returning a pointer). Vector2 is a light structure and pointers are very likely to cause headaches in this context (where are you going to delete it, and so on). Also note that I used 'const' references as we do not modify them, except the vector. For this one we want a local copy, this is why it is not a reference at all.

like image 78
Jean Avatar answered Dec 04 '22 13:12

Jean


Previous code only work if you do not do any rotations (for eg. GL.Rotate(rotation_x, 1.0, 0.0, 0.0)). But if you do here is the code:

private Vector2 Convert(Vector3 pos, Matrix4 viewMatrix, Matrix4 projectionMatrix, int screenWidth, int screenHeight)
{
    pos = Vector3.Transform(pos, viewMatrix);
    pos = Vector3.Transform(pos, projectionMatrix);
    pos.X /= pos.Z;
    pos.Y /= pos.Z;
    pos.X = (pos.X + 1) * screenWidth / 2;
    pos.Y = (pos.Y + 1) * screenHeight / 2;

    return new Vector2(pos.X, pos.Y);
}
like image 38
skolko Avatar answered Dec 04 '22 11:12

skolko