Пересечение лучей с трехмерными квадраторами в XNA?

Итак, я успешно сделал луч, который представляет мышь, не спроецированную в мир, и теперь мне нужно проверить, может ли этот луч пересекаться с четырехугольным объектом, вот код, который я использую, чтобы получить луч:

public Ray GetMouseRay()
    {
        Vector2 mousePosition = new Vector2(cursor.getX(), cursor.getY());

        Vector3 nearPoint = new Vector3(mousePosition, 0);
        Vector3 farPoint = new Vector3(mousePosition, 1);

        nearPoint = viewport.Unproject(nearPoint, projectionMatrix, viewMatrix, Matrix.Identity);
        farPoint = viewport.Unproject(farPoint, projectionMatrix, viewMatrix, Matrix.Identity);

        Vector3 direction = farPoint - nearPoint;
        direction.Normalize();

        return new Ray(nearPoint, direction);
    }

И, аналогично, это моя четырехугольная структура, которую я использую, чтобы нарисовать "кубический мир" в трехмерном пространстве. публичная структура Quad {публичный Vector3 Origin; общедоступный Vector3 UpperLeft; общедоступный Vector3 LowerLeft; общедоступный Vector3 UpperRight; публичный Vector3 LowerRight; общедоступный Vector3 Normal; общедоступный Vector3 Up; общедоступный Vector3 Left;

    public VertexPositionNormalTexture[] Vertices;
      public int[] Indexes;
    public short[] Indexes;


    public Quad( Vector3 origin, Vector3 normal, Vector3 up, 
        float width, float height )
    {
        Vertices = new VertexPositionNormalTexture[4];
        Indexes = new short[6];
        Origin = origin;
        Normal = normal;
        Up = up;

        // Calculate the quad corners
        Left = Vector3.Cross( normal, Up );
        Vector3 uppercenter = (Up * height / 2) + origin;
        UpperLeft = uppercenter + (Left * width / 2);
        UpperRight = uppercenter - (Left * width / 2);
        LowerLeft = UpperLeft - (Up * height);
        LowerRight = UpperRight - (Up * height);

        FillVertices();
    }

    private void FillVertices()
    {
        // Fill in texture coordinates to display full texture
        // on quad
        Vector2 textureUpperLeft = new Vector2( 0.0f, 0.0f );
        Vector2 textureUpperRight = new Vector2( 1.0f, 0.0f );
        Vector2 textureLowerLeft = new Vector2( 0.0f, 1.0f );
        Vector2 textureLowerRight = new Vector2( 1.0f, 1.0f );

        // Provide a normal for each vertex
        for (int i = 0; i < Vertices.Length; i++)
        {
            Vertices[i].Normal = Normal;
        }

        // Set the position and texture coordinate for each
        // vertex
        Vertices[0].Position = LowerLeft;
        Vertices[0].TextureCoordinate = textureLowerLeft;
        Vertices[1].Position = UpperLeft;
        Vertices[1].TextureCoordinate = textureUpperLeft;
        Vertices[2].Position = LowerRight;
        Vertices[2].TextureCoordinate = textureLowerRight;
        Vertices[3].Position = UpperRight;
        Vertices[3].TextureCoordinate = textureUpperRight;

        // Set the index buffer for each vertex, using
        // clockwise winding
        Indexes[0] = 0;
        Indexes[1] = 1;
        Indexes[2] = 2;
        Indexes[3] = 2;
        Indexes[4] = 1;
        Indexes[5] = 3;
    }
}

Я обнаружил, что в классе лучей есть метод intersects(), который принимает в качестве параметра плоскостную структуру, а плоскостная структура принимает в конструкторе нормаль и расстояние от начала координат, но мои плоскости имеют позицию и нормаль, а не просто расстояние от начала координат. поэтому я не могу их преобразовать. Как я могу определить, пересекается ли мой луч с моей четырехугольной структурой?

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

Спасибо за чтение, я понимаю, что этот вопрос является немного длинным, и спасибо заранее.

3 ответа

Решение

Я не уверен точно, что они имеют в виду под "расстоянием по нормали от начала координат", но я бы предположил, что это просто означает расстояние от начала координат. Вы можете получить это из свойства length в Vector3.

Если это не сработает, есть также конструктор для плоскости, который принимает три точки на плоскости:

public Plane (
     Vector3 point1,
     Vector3 point2,
     Vector3 point3
)

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

Поскольку вы используете кубы, вы можете использовать Ray.Intersects(Plane) метод. Вам просто нужно еще несколько самолетов.

Определив первую точку пересечения, вы можете построить больше плоскостей для каждой перпендикулярной грани вашего куба. Тогда вы можете использовать Plane.Distance(Vector3) (Я почти уверен, что это или что-то подобное существует), чтобы убедиться, что ваша точка находится между каждой парой перпендикулярных плоскостей. Если это не между ними, то вы можете игнорировать пересечение.

Не совсем прямой ответ на ваш вопрос, но, возможно, вы найдете это актуальным.

Рассматривали ли вы создание объекта BoundingBox и использовать пересечения (луч)? http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.boundingbox.intersects.aspx

Редактировать 1: Так я обычно делаю. В зависимости от вашей структуры данных, также может быть проще оптимизировать (например, если вы создаете большие ограничивающие рамки, в которые можно врезаться).

Редактировать 2: Согласно предложению Нико: я не хочу публиковать соответствующий код (потому что это всего пара страниц, чтобы сделать контекст понятным) из примеров, но я могу указать вам на части, которые вы ' будет интересно

  1. Загрузите образец с http://xbox.create.msdn.com/en-US/education/catalog/sample/picking_triangle
  2. В нижней части файла Cursor.cs содержится то, что вы уже знаете, вычисляя луч
  3. Перейдите в файл Game.cs. Там вы найдете UpdatePicking(), который вызывает RayIntersectsModel (...), который вызывает RayIntersectsTriangle (...)

Преобразование Луча - это часть:

Matrix inverseTransform = Matrix.Invert( modelTransform );

ray.Position = Vector3.Transform( ray.Position, inverseTransform );
ray.Direction = Vector3.TransformNormal( ray.Direction, inverseTransform );

Насколько глубоко вы хотите пойти (насколько точно ваш выбор), конечно, соответствует вашим потребностям, но у вас это есть.

Другие вопросы по тегам