Projecting a 3D point to 2D screen coordinate OpenTK

南笙酒味 提交于 2019-12-08 01:46:28

问题


Using Monotouch and OpenTK I am trying to get the screen coordinate of one 3D point. I have my world view projection matrix set up, and OpenGL makes sense of it and projects my 3D model perfectly, but how to use the same matrix to project just one point from 2D to 3D?

I thought I could simply use:

Vector3.Transform(ref input3Dpos, ref matWorldViewProjection, out projected2Dpos);

Then have the projected screen coordinate in projected2DPos. But the resulting Vector4 does not seem to represent the proper projected screen coordinate. And I do not know how to calculate it from there on.


I found I need to divide by Vector4.w, however I am still getting the wrong values. Using this method now:

private static bool GluProject(OpenTK.Vector3 objPos, OpenTK.Matrix4 matWorldViewProjection, int[] viewport, out OpenTK.Vector3 screenPos)
{
    OpenTK.Vector4 _in;

    _in.X = objPos.X;
    _in.Y = objPos.Y;
    _in.Z = objPos.Z;
    _in.W = 1f;

    Vector4 _out = OpenTK.Vector4.Transform(_in, matWorldViewProjection);

    if (_out.W <= 0.0)
    {
        screenPos = OpenTK.Vector3.Zero;
        return false;
    }

    _out.X /= _out.W;
    _out.Y /= _out.W;
    _out.Z /= _out.W;
    /* Map x, y and z to range 0-1 */
    _out.X = _out.X * 0.5f + 0.5f;
    _out.Y = -_out.Y * 0.5f + 0.5f;
    _out.Z = _out.Z * 0.5f + 0.5f;

    /* Map x,y to viewport */
    _out.X = _out.X * viewport[2] + viewport[0];
    _out.Y = _out.Y * viewport[3] + viewport[1];

    screenPos.X = _out.X;
    screenPos.Y = _out.Y;
    screenPos.Z = _out.Z;

    return true;
}

I cannot see any errors though... :S


回答1:


In the first question you're missing the last step: Mapping from NDC (Normalized Device Coordinates) to viewport coordinates. That's what the lines

/* Map x,y to viewport */
_out.X = _out.X * viewport[2] + viewport[0];
_out.Y = _out.Y * viewport[3] + viewport[1];

in your GluProject do,




回答2:


You have two options. You can calculate it yourself, or use the glProject function. I prefer the first.

Number 1:

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);
}

Number 2:

public Vector2 form3Dto2D(Vector3 our3DPoint)
{
    Vector3 our2DPoint;

    float[] modelviewMatrix =  new float[16];
    float[] projectionMatrix = new float[16];
    int[] viewport = new int[4];

    GL.GetFloat(GetPName.ModelviewMatrix, modelviewMatrix);
    GL.GetFloat(GetPName.ProjectionMatrix, projectionMatrix);
    GL.GetInteger(GetPName.Viewport, viewport);

    OpenTK.Graphics.Glu.Project(our3DPoint, convertFloatsToDoubles(modelviewMatrix),
        convertFloatsToDoubles(projectionMatrix), viewport, out our2DPoint);

    return new Vector2(our2DPoint.X, our2DPoint.Y)
}   

public static double[] convertFloatsToDoubles(float[] input)
{
    if (input == null)
    {
        return null; // Or throw an exception - your choice
    }

    double[] output = new double[input.Length];
    for (int i = 0; i < input.Length; i++)
    {
        output[i] = input[i];
    }
    return output;
}


来源:https://stackoverflow.com/questions/7697014/projecting-a-3d-point-to-2d-screen-coordinate-opentk

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!