В примере, который я хочу использовать для демонстрации своей проблемы, у меня есть одна модель турбины и небольшая сетка, как показано на изображениях ниже. Ограничительная рамка модели отображается как красная рамка. Я пытаюсь проверить, какие узлы в моей зеленой сетке лежат над ограничительной рамкой турбины. Если узел находится над ограничивающей рамкой, я немного перемещаю его вниз, чтобы четко видеть, какие узлы находятся над ограничивающей рамкой, а какие нет.
Как вы можете видеть на первом изображении, он отлично работает для моей модели без поворота. Однако, если я поверну модель на -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);
}
Ограничительная рамка идеально подходит для моей модели турбины в обеих моделях. В то время как модель преобразуется на графическом процессоре для каждой позиции, ограничивающая рамка преобразуется кодом, показанным выше. Поскольку модель и ограничение подходят, я считаю, что их расчет работает.
Но я не понимаю, почему мои тесты попадания работают для невращаемого объекта, а я не работаю для повернутого.
Есть ли у вас какие-либо идеи?