3D Hit Testing в WPF

Я пишу приложение WPF, которое отображает рельеф в 3D.

Когда я выполняю проверку попадания, возвращается неправильная 3D-точка (не точка, на которой я щелкнул).

Я попытался выделить треугольник, в который попал (создав новую сетку, взяв координаты из объекта RayMeshGeometry3DHitTestResult). Я вижу, что попал не в тот треугольник (треугольник выделен, но не под курсором).

Я использую перспективную камеру с полем зрения 60, а ближняя и дальняя плоскости 3 и 35000 соответственно.

Есть идеи, почему это могло произойти, и что я могу сделать, чтобы решить эту проблему?

Дайте мне знать, если вам понадобятся дополнительные данные.

Изменить: это код, который я использую для проверки попадания:

private void m_viewport3d_MouseDown(object sender, MouseButtonEventArgs e)
{
    Point mousePos = e.GetPosition(m_viewport3d);
    PointHitTestParameters hitParams = new PointHitTestParameters(mousePos);
    HitTestResult result = VisualTreeHelper.HitTest(m_viewport3d, mousePos);
    RayMeshGeometry3DHitTestResult rayMeshResult = result as RayMeshGeometry3DHitTestResult;
    if (rayMeshResult != null)
    {
        MeshGeometry3D mesh = new MeshGeometry3D();
        mesh.Positions.Add(rayMeshResult.MeshHit.Positions[rayMeshResult.VertexIndex1]);
        mesh.Positions.Add(rayMeshResult.MeshHit.Positions[rayMeshResult.VertexIndex2]);
        mesh.Positions.Add(rayMeshResult.MeshHit.Positions[rayMeshResult.VertexIndex3]);
        mesh.TriangleIndices.Add(0);
        mesh.TriangleIndices.Add(1);
        mesh.TriangleIndices.Add(2);
        GeometryModel3D marker = new GeometryModel3D(mesh, new DiffuseMaterial(Brushes.Blue));
        //...add marker to the scene...
    }
}

person Itai Bar-Haim    schedule 25.07.2011    source источник
comment
мы не можем отлаживать, не видя вашего кода   -  person Robert Levy    schedule 25.07.2011
comment
Ну, это много кода ... Я строю ландшафт, используя плитки разного размера (выбранные с помощью механизма, подобного дереву квадрантов, аналогично тому, как работает Google Планета Земля). Плитки размещаются в координатах ECEF (геоцентрических), поэтому единицы измерения - метры. Я постараюсь сделать простую демонстрацию, которая продемонстрирует это, и опубликую ее позже.   -  person Itai Bar-Haim    schedule 25.07.2011
comment
было бы полезно небольшое приложение, которое воспроизводит проблему. либо есть ошибка в способе проверки попадания, либо в способе выделения. если вы не можете опубликовать код, попробуйте визуализировать луч, который вы используете для проверки попадания, чтобы убедиться, что он действительно находится там, где вы думаете   -  person Robert Levy    schedule 25.07.2011
comment
Я хотел нарисовать луч, но объект RayMeshGeometry3DHitTestResult дает мне только точку попадания, а не параметры луча (начало и направление). Есть предложения, как их получить? (используя отражение, возможно, для имитации проверки попадания?)   -  person Itai Bar-Haim    schedule 25.07.2011
comment
ах, теперь проблема ясна :) WPF не знает, в каком направлении вы пытаетесь провести тест на попадание ... вам нужно дать ему луч. См. Мой ответ, который ссылается на правильный метод HitTest. Если это поможет, нажмите на галочку рядом с ним.   -  person Robert Levy    schedule 25.07.2011
comment
AFAIK WPF генерирует (надеюсь) правильный луч для проверки попадания, поэтому, если я правильно вас понял, вы хотите, чтобы я сгенерировал этот луч вручную?   -  person Itai Bar-Haim    schedule 26.07.2011
comment
Мне удалось получить и нарисовать луч, отбрасываемый из положения мыши, и, похоже, это не имеет ничего общего с положением мыши ... Как я могу убедиться, что луч правильно отбрасывается из усеченной пирамиды камеры?   -  person Itai Bar-Haim    schedule 26.07.2011
comment
Имеет ли значение, что элемент управления Viewport3D размещен в сетке, которая размещена в UserControl, который размещен в WinForms ElementHost, представленной на плавающей панели, предоставляемой Syncfusion? Я спрашиваю, потому что у меня нет других идей. Я уже пробовал использовать библиотеку Петцольда, чтобы вручную отбросить луч, и получил те же результаты ...   -  person Itai Bar-Haim    schedule 26.07.2011


Ответы (3)


Что меня поразило, так это то, что точки были в координатах модели. Пришлось трансформироваться в мировые координаты. Вот мой код, который выполняет проверку попадания (он вернет все попадания под курсором, а не только первые):

//  This will cast a ray from the point (on _viewport) along the direction that the camera is looking, and returns hits
private List<RayMeshGeometry3DHitTestResult> CastRay(Point clickPoint, IEnumerable<Visual3D> ignoreVisuals)
{
    List<RayMeshGeometry3DHitTestResult> retVal = new List<RayMeshGeometry3DHitTestResult>();

    //  This gets called every time there is a hit
    HitTestResultCallback resultCallback = delegate(HitTestResult result)
    {
        if (result is RayMeshGeometry3DHitTestResult)       //  It could also be a RayHitTestResult, which isn't as exact as RayMeshGeometry3DHitTestResult
        {
            RayMeshGeometry3DHitTestResult resultCast = (RayMeshGeometry3DHitTestResult)result;
            if (ignoreVisuals == null || !ignoreVisuals.Any(o => o == resultCast.VisualHit))
            {
                retVal.Add(resultCast);
            }
        }

        return HitTestResultBehavior.Continue;
    };

    //  Get hits against existing models
    VisualTreeHelper.HitTest(grdViewPort, null, resultCallback, new PointHitTestParameters(clickPoint));

    //  Exit Function
    return retVal;
}

И немного логики, потребляющей хит:

if (hit.VisualHit.Transform != null)
{
    return hit.VisualHit.Transform.Transform(hit.PointHit);
}
else
{
    return hit.PointHit;
}
person Charlie    schedule 31.03.2012
comment
Это было очень полезно, спасибо. Именно это мне и нужно для моего сценария. - person Daniel Leiszen; 10.09.2014

Вам необходимо предоставить луч для проверки попадания, чтобы это работало в 3D. Используйте правильную перегрузку VisualTreeHelper.HitTest, которая принимает Visual3D и RayHitTestParameters: http://msdn.microsoft.com/en-us/library/ms608751.aspx

person Robert Levy    schedule 25.07.2011

Оказывается, это была Normalize проблема. Я не должен был нормализовать взгляды камеры и векторы вверх. В шкалах, которые я использую, искажение слишком велико для корректной работы теста нажатия.

person Itai Bar-Haim    schedule 26.07.2011