Тесты попаданий в SharpDX не работают после поворота модели

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

Как вы можете видеть на первом изображении, он отлично работает для моей модели без поворота. Однако, если я поверну модель на -90°, все тесты на попадание не пройдут. Я не понимаю, почему это происходит! У меня та же проблема, когда я выполняю тесты на попадание для «Выбора».

введите здесь описание изображения

введите здесь описание изображения

Вот моя небольшая функция, которую я использую, чтобы проверить, находится ли узел над какой-либо ограничивающей рамкой или нет. Для этой задачи я создаю луч для каждого из моих узлов, который указывает на дно. Затем я проверяю этот луч на пересечение со всеми позициями всех моих моделей. (Если бы у меня было несколько турбин, я бы использовал только модель турбины, но в нескольких положениях. Это ускоряет рендеринг на графическом процессоре.)

foreach (var node in level.VisualGraph.Nodes)
{
    SharpDX.Vector3 upperVector = new SharpDX.Vector3(node.Position.X, 1.0f, node.Position.Z);

    SharpDX.Ray ray = new SharpDX.Ray(upperVector, new SharpDX.Vector3(0.0f, -1.0f, 0.0f));
    foreach (var model in level.Models)
    {
        foreach (var position in model.Positions)
        {
            if (position.BoundingBox.GeometricBoundingBox.Intersects(ref ray))
            {
                node.Position = new SharpDX.Vector3(node.Position.X, 0.6f, node.Position.Z);
                break;
            }
        }
    }
}

Как отмечалось ранее, каждая модель может встречаться в сцене несколько раз, поэтому я сохраняю каждую модель только один раз и вычисляю трансформацию для каждой ее позиции. Таким образом, для каждой позиции модели существует одна ограничивающая рамка.

«GeometricBoundingBox», который я использую для теста попадания, имеет тип SharpDX.BoundingBox. Когда я добавляю новую позицию в свою модель, я создаю новую ограничивающую рамку, проверяя все вершины модели на ее минимум и максимум.

bool isFirst = true;
foreach (var vertex in vertices)
{
    if (isFirst)
    {
        _min = new SharpDX.Vector3(vertex.GetPosition().X, vertex.GetPosition().Y, vertex.GetPosition().Z);
        _max = new SharpDX.Vector3(vertex.GetPosition().X, vertex.GetPosition().Y, vertex.GetPosition().Z);

        isFirst = false;
    }
    else
    {
        _min.X = Math.Min(_min.X, vertex.GetPosition().X);
        _min.Y = Math.Min(_min.Y, vertex.GetPosition().Y);
        _min.Z = Math.Min(_min.Z, vertex.GetPosition().Z);

        _max.X = Math.Max(_max.X, vertex.GetPosition().X);
        _max.Y = Math.Max(_max.Y, vertex.GetPosition().Y);
        _max.Z = Math.Max(_max.Z, vertex.GetPosition().Z);
    }
}

Когда ограничивающая рамка создается в первый раз или всякий раз, когда мировая матрица родительской позиции изменяется, я вычисляю свой «GeometricBoundingBox» следующим образом:

SharpDX.Vector4 testMin = Helper.Math.Multiply(new SharpDX.Vector4(_min, 1.0f), worldMatrix);
SharpDX.Vector4 testMax = Helper.Math.Multiply(new SharpDX.Vector4(_max, 1.0f), worldMatrix);

GeometricBoundingBox = new SharpDX.BoundingBox(new SharpDX.Vector3(testMin.X, testMin.Y, testMin.Z), new SharpDX.Vector3(testMax.X, testMax.Y, testMax.Z));

Мировая матрица, которая используется для преобразования модели позиции, также используется для вычисления ограничивающей рамки, как показано выше. Я рассчитываю так:

public void UpdateWorldMatrix()
{
    SharpDX.Matrix rotationMatrix = SharpDX.Matrix.RotationYawPitchRoll(RotationY, RotationX, RotationZ);

    // We need to calculate the transformation matrix once and apply it for the initial offset before we can calculate the final matrix.
    SharpDX.Matrix initialMatrix = SharpDX.Matrix.Scaling(Scaling * _parentModel.InitialScaling) * rotationMatrix;
    SharpDX.Vector3 initialTranslation = Helper.Converters.ToVector(Helper.Math.Multiply2(_parentModel.InitialTranslation, initialMatrix));

    // Calculate world matrix and update bounding box.
    WorldMatrix = SharpDX.Matrix.Scaling(Scaling * _parentModel.InitialScaling) * rotationMatrix * SharpDX.Matrix.Translation(Position + Translation + initialTranslation);

    if (ParentStaticPosition != null)
        WorldMatrix = SharpDX.Matrix.Multiply(WorldMatrix, ParentStaticPosition.WorldMatrix);

    BoundingBox.ReBuild(WorldMatrix);
}

Ограничительная рамка идеально подходит для моей модели турбины в обеих моделях. В то время как модель преобразуется на графическом процессоре для каждой позиции, ограничивающая рамка преобразуется кодом, показанным выше. Поскольку модель и ограничение подходят, я считаю, что их расчет работает.

Но я не понимаю, почему мои тесты попадания работают для невращаемого объекта, а я не работаю для повернутого.

Есть ли у вас какие-либо идеи?


person Endgegner85    schedule 14.02.2017    source источник


Ответы (1)


Одна вещь, которую вы можете сделать, что я делаю для приведения лучей, - это преобразовать луч в пространство модели, а не преобразовывать ограничивающую рамку в вашу ориентацию. Это делается путем взятия обратной матрицы матрицы ориентации модели и умножения вашей начальной и конечной точек вашего вектора на обратную. Затем создаем луч в пространстве модели и приводим его к пространству модели aabb.

Если вы ориентируете свой aabb по матрице, это не сработает. Вам нужно пересчитать новый aabb, умножив каждую вершину в модели на матрицу ориентации, а затем пересчитать aabb. Я считаю, что это то, что вы делаете, но я считаю, что ограничивающая рамка, которую вы трансформируете, может не иметь правильных максимальных минимальных размеров.

person ErnieDingo    schedule 14.02.2017
comment
Это.. это работает. Но почему? Я имею в виду, я делаю то же самое, что и раньше, но только в другом пространстве, верно? Не могли бы вы дать мне дополнительную информацию, ЭрниДинго? Я хотел бы понять, почему ваш подход сработал, а мой не сработал для некоторых повернутых элементов! - person Endgegner85; 14.02.2017
comment
Я предполагаю, что это только потому, что ваши минимальные и максимальные экстенты рассчитаны неправильно. Простое их вращение означает, что они больше не являются минимальными максимальными экстентами. Вы должны полностью пересчитать их из своей матрицы ориентации. Я бы посоветовал просто делать ваши лучи в пространстве модели, потому что это быстрее, чем делать это против ориентированной модели. - person ErnieDingo; 15.02.2017