【问题标题】:Projecting a 3D point to 2D screen coordinate OpenTK将 3D 点投影到 2D 屏幕坐标 OpenTK
【发布时间】:2023-03-03 00:12:01
【问题描述】:

使用 Monotouch 和 OpenTK,我试图获取一个 3D 点的屏幕坐标。我已经设置了世界视图投影矩阵,OpenGL 可以理解它并完美地投影我的 3D 模型,但是如何使用相同的矩阵将仅一个点从 2D 投影到 3D?

我以为我可以简单地使用:

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

然后在projected2DPos 中获得投影屏幕坐标。但生成的 Vector4 似乎并不代表正确的投影屏幕坐标。而且我不知道如何从那里计算出来。


我发现我需要除以 Vector4.w,但我仍然得到错误的值。现在使用这个方法:

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

虽然我看不到任何错误... :S

【问题讨论】:

    标签: opengl 3d projection opentk


    【解决方案1】:

    在第一个问题中,您错过了最后一步:从 NDC(标准化设备坐标)映射到视口坐标。就是这样的台词

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

    在你的GluProject 做,

    【讨论】:

    • 我刚刚意识到我在世界矩阵中提供了两次信息,一次作为传入点 (objPos),另一次作为给定矩阵的一部分。这导致了奇怪的结果。它仅在输入组合视图和投影矩阵后起作用。 :)
    【解决方案2】:

    你有两个选择。你可以自己计算,或者使用glProject函数。我更喜欢第一个。

    一号:

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

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

    【讨论】:

    • 在数字 1 中,我们到底为什么要除以 pos.Z?!值不应该除以齐次坐标系的w分量吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多