Проецирование 3D-точки в 2D-координату экрана OpenTK - PullRequest
2 голосов
/ 08 октября 2011

Используя 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

Ответы [ 2 ]

1 голос
/ 03 октября 2012

У вас есть два варианта.Вы можете рассчитать это самостоятельно или использовать функцию glProject.Я предпочитаю первое.

Номер 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);
}

Номер 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 голос
/ 08 октября 2011

В первом вопросе вы пропускаете последний шаг: отображение из NDC (нормализованные координаты устройства) в координаты области просмотра. Это то, что линии

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

в вашем GluProject до

...