Как вращать, масштабировать и переводить матрицу одновременно в C #? - PullRequest
8 голосов
/ 11 марта 2009

Хорошо, это должен быть простой вопрос о матрицах, но мое понимание матриц несколько ограничено. Вот сценарий: у меня есть спрайт 1 на 1 пиксель, который я хочу масштабировать до некоторой величины x и y (разные суммы с каждой стороны), а затем я хочу повернуть этот спрайт на некоторый угол, а затем я хочу иметь возможность точно расположите все это (сверху слева или по центру, мне все равно).

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

Я бы подумал, что это сделает это:

        Point center = new Point( 50, 50 );
        float width = 60;
        float height = 100;
        float angle = 0.5;
        Vector3 axis = new Vector3( center.X, center.Y, 0 );
        axis.Normalize();
        Matrix m = Matrix.Scaling( width, height, 0 ) *
            Matrix.RotationAxis( axis, angle ) *
            Matrix.Translation( center.X, center.Y, 0 );

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

Я тоже пробовал это:

  Matrix m = Matrix.Transformation2D( new Vector2( center.X, center.Y ), 0f,
      new Vector2( width, height ), new Vector2( center.X, center.Y ),
      angle, Vector2.Zero );

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

Это все в SlimDX. Что я делаю не так?

Ответы [ 4 ]

12 голосов
/ 11 марта 2009

Я только что прошел через обучение обучению преобразованию матриц, но с использованием XNA.

Я нашел эти статьи до , которые были бы очень полезными для понимания того, что происходит. Вызовы методов очень похожи в XNA, и теория, лежащая в их основе, должна применяться к вам, даже с SlimDX.

От просмотра вашего кода, я думаю, вам следует переводить в начале, в начало, а затем снова переводить в конце, в конечную позицию, хотя я все еще немного новичок в этом, как хорошо.

Порядок, в котором я бы это сделал:

  • Перевести на место происхождения
  • Масштаб
  • Поворот
  • Перевести в нужное место

Причина перевода в начало координат заключается в том, что повороты основаны на источнике . Поэтому, чтобы вращать что-то относительно определенной точки, поместите эту точку на начало координат, прежде чем вращать.

3 голосов
/ 12 марта 2009

Хорошо, теперь это работает. Вот мой рабочий код для этого, на случай, если кому-то еще это понадобится:

    Point sourceLoc = new Point ( 50, 50 );
    float length = 60;
    float thickness = 2;
    float angle = 0.5;
    Matrix m = Matrix.Scaling( length, thickness, 0 ) *
            Matrix.RotationZ( angle ) *
            Matrix.Translation( sourceLoc.X, sourceLoc.Y, 0 );
    sprite.Transform = m;

    sprite.Draw( this.tx, Vector3.Zero, Vector3.Zero, Color.Red );

Это нарисует наклонную линию выбранной вами длины с толщиной, равной выбранной вами толщине (при условии, что ваша текстура представляет собой белое изображение размером 1x1 пиксель). Местоположение источника - это то, откуда будет исходить линия, с любым указанным вами углом (в радианах). Таким образом, если вы начнете с нуля и увеличитесь на что-то вроде 0,1, пока не достигнете 2PI, а затем сброситесь до 0, у вас будет линия, которая вращается вокруг центра, как стрелка часов или развертка радара. Это то, что я искал - спасибо всем, кто внес свой вклад!

1 голос
/ 11 марта 2009

Вы вращаетесь вокруг правильной оси? Я новичок в матричных вещах, но мне кажется, что, поскольку спрайт существует в пространстве x, y, ось вращения должна быть осью Z - т.е. (0,0,1).

1 голос
/ 11 марта 2009

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

Вы также можете нарисовать временные линии, чтобы помочь определить, где находятся координаты. Например, если вы выполняете растяжение и вращение и ожидаете, что конечная точка будет равна 0,0. Рисование другой линии с одной конечной точкой в ​​0,0 будет двойной проверкой, чтобы увидеть, так ли это на самом деле.

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

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

ОТВЕТ НА КОММЕНТАРИИ

Если перевод является проблемой, и вы преобразуете систему координат, то вам нужно написать функцию преобразования для преобразования между старой системой и новой.

Например, если вы поворачиваетесь на 45 градусов. Перед вращением вы могли бы перевести на 0,1, чтобы двигаться вверх на 1 дюйм. После поворота вам придется переводить примерно на -70707, .070707, чтобы переместиться на 1 дюйм относительно исходной системы координат.

...