3D-матрица вращения со временем деформируется в Processing / Java - PullRequest
1 голос
/ 26 апреля 2011

Я работаю над проектом, в котором я хочу создать трехмерную сетку для представления определенного количества данных.

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

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

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

Я определил координаты прямоугольника и провел их через матрицу преобразования, прежде чем записать их на экран

Это формула вращения моего объекта

    void appendRotation(float inXAngle, float inYAngle, float inZAngle, PVector inPivot ) {

    boolean setPivot = false;

    if (inPivot.x != 0 || inPivot.y != 0 || inPivot.z != 0) {
        setPivot = true;
    }

    // If a setPivot = true, translate the position
    if (setPivot) {

        // Translations for the different axises need to be set different
        if (inPivot.x != 0) { this.appendTranslation(inPivot.x,0,0); }
        if (inPivot.y != 0) { this.appendTranslation(0,inPivot.y,0); }
        if (inPivot.z != 0) { this.appendTranslation(0,0,inPivot.z); }

    }

    // Create a rotationmatrix
    Matrix3D rotationMatrix = new Matrix3D();

    // xsin en xcos
    float xSinCal = sin(radians(inXAngle));
    float xCosCal = cos(radians(inXAngle));      
    // ysin en ycos
    float ySinCal = sin(radians(inYAngle));
    float yCosCal = cos(radians(inYAngle));     
    // zsin en zcos
    float zSinCal = sin(radians(inZAngle));
    float zCosCal = cos(radians(inZAngle));           

    // Rotate around x
    rotationMatrix.setIdentity();
    // --
    rotationMatrix.matrix[1][1] = xCosCal;
    rotationMatrix.matrix[1][2] = xSinCal;
    rotationMatrix.matrix[2][1] = -xSinCal;
    rotationMatrix.matrix[2][2] = xCosCal;
    // Add rotation to the basis matrix
    this.multiplyWith(rotationMatrix);

    // Rotate around y
    rotationMatrix.setIdentity();
    // --
    rotationMatrix.matrix[0][0] = yCosCal;
    rotationMatrix.matrix[0][2] = -ySinCal;
    rotationMatrix.matrix[2][0] = ySinCal;
    rotationMatrix.matrix[2][2] = yCosCal;
    // Add rotation to the basis matrix
    this.multiplyWith(rotationMatrix);

    // Rotate around z
    rotationMatrix.setIdentity();
    // --
    rotationMatrix.matrix[0][0] = zCosCal;
    rotationMatrix.matrix[0][1] = zSinCal;
    rotationMatrix.matrix[1][0] = -zSinCal;
    rotationMatrix.matrix[1][1] = zCosCal;
    // Add rotation to the basis matrix
    this.multiplyWith(rotationMatrix);

    // Untranslate the position
    if (setPivot) {

        // Translations for the different axises need to be set different
        if (inPivot.x != 0) { this.appendTranslation(-inPivot.x,0,0); }
        if (inPivot.y != 0) { this.appendTranslation(0,-inPivot.y,0); }
        if (inPivot.z != 0) { this.appendTranslation(0,0,-inPivot.z); }

    }

}

У кого-нибудь есть подсказка?

Ответы [ 5 ]

2 голосов
/ 26 апреля 2011

Вы никогда не хотите кумулятивно преобразовывать матрицы.Это внесет ошибку в ваши матрицы и вызовет проблемы, такие как масштабирование или перекос ортогональных компонентов.

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

1 голос
/ 27 апреля 2011

Как упоминает @don, старайтесь избегать кумулятивных преобразований, так как вы можете столкнуться с всевозможными проблемами. Поворот по одной оси за раз может привести к проблемам Gimbal Lock . Попробуйте сделать все повороты за один раз.

Кроме того, следует помнить, что обработка поставляется с собственным классом Matrix3D с именем PMatrix3D , который имеет метод rotate () , который принимает угол (в радианах) и x, y, значения z для оси вращения.

Вот пример функции, которая будет вращать кучу PVectors:

PVector[] rotateVerts(PVector[] verts,float angle,PVector axis){
  int vl = verts.length;
  PVector[] clone = new PVector[vl];
  for(int i = 0; i<vl;i++) clone[i] = verts[i].get();
  //rotate using a matrix
  PMatrix3D rMat = new PMatrix3D();
  rMat.rotate(angle,axis.x,axis.y,axis.z);
  PVector[] dst = new PVector[vl];
  for(int i = 0; i<vl;i++) {
    dst[i] = new PVector();
    rMat.mult(clone[i],dst[i]);
  }
  return dst;
}

и вот пример с его использованием.

rotation matrix

НТН

1 голос
/ 27 апреля 2011

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

Если невозможно избежать умножения матриц вращения, перенормируйте их (стр. 16). У меня это отлично работает для более чем 10 тысяч умножений.

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

Тяга, тангаж и крен не подходят для произвольных вращений . Углы Эйлера страдают от особенностей и нестабильности. Посмотрите на 38:25 (презентация Дэвида Сакса)

http://www.youtube.com/watch?v=C7JQ7Rpwn2k

Удачи!

0 голосов
/ 13 января 2015

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

Хорошей исходной информацией для реализации этого может быть:

Полезная академическая справка может быть:

  • K.Шумейк, «Анимация вращения с помощью кватернионных кривых», ACM SIGGRAPH Comput.Graph., Vol.19, нет3, с. 245–254, 1985. DOI: 10.1145 / 325165.325242
0 голосов
/ 27 апреля 2011

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

void setIdentity() {  
    this.matrix = identityMatrix;
}

Вы уверены, что делаете копию?identityMatrix?Если это просто ссылка, которую вы копируете, то identityMatrix будет изменен последующими операциями, и вскоре ничего не будет иметь смысла.

...