Как решена проблема с карданной решеткой с использованием накопительных матричных преобразований

Я читаю онлайн-книгу «Изучение современной 3D-графики» Джейсона Л. Маккессона

На данный момент я занимаюсь проблемой блокировки карданных и как ее решить с помощью кватернионов.

Однако здесь, на странице Quaternions .

  

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

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

также:

  

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

     

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

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

Вот код:

void display()
{
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClearDepth(1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutil::MatrixStack currMatrix;
    currMatrix.Translate(glm::vec3(0.0f, 0.0f, -200.0f));
    currMatrix.RotateX(g_angles.fAngleX);
    DrawGimbal(currMatrix, GIMBAL_X_AXIS, glm::vec4(0.4f, 0.4f, 1.0f, 1.0f));
    currMatrix.RotateY(g_angles.fAngleY);
    DrawGimbal(currMatrix, GIMBAL_Y_AXIS, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
    currMatrix.RotateZ(g_angles.fAngleZ);
    DrawGimbal(currMatrix, GIMBAL_Z_AXIS, glm::vec4(1.0f, 0.3f, 0.3f, 1.0f));

    glUseProgram(theProgram);
    currMatrix.Scale(3.0, 3.0, 3.0);
    currMatrix.RotateX(-90);
    //Set the base color for this object.
    glUniform4f(baseColorUnif, 1.0, 1.0, 1.0, 1.0);
    glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));

    g_pObject->Render("tint");

    glUseProgram(0);

    glutSwapBuffers();
}

Насколько я понимаю, это не то, что он делает (модифицируя матрицу в стеке), считая накопительные матрицы, поскольку автор объединил все отдельные преобразования вращения в одну матрицу, которая хранится в верхней части стека.

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

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

Вот почему габаритный замок происходит правильно? Это связано с тем, что мы вращаем объект вокруг осей X, Y и Z вместо поворота объекта вокруг его собственных осей relative . Или я не прав?

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

Итак, вкратце:

  • В чем разница между поворотом и ориентацией?
  • Почему код не связан с примером накопления матричных преобразований?
  • Какова реальная конкретная цель матрицы, если я ошибался?
  • Как можно реализовать решение проблемы блокировки карданов с помощью накопления матричных преобразований?
  • Кроме того, в качестве бонуса: почему преобразования после вращения по-прежнему относятся к «пространству модели?»
  • Еще один бонус: я ошибаюсь в предположении, что после преобразования последующие преобразования будут происходить относительно текущего?

Кроме того, если это не подразумевалось, я использую OpenGL, GLSL, C ++ и GLM, поэтому примеры и объяснения в терминах этих систем очень ценятся, если это не необходимо.

Чем детальнее, тем лучше!

Спасибо заранее.

9 голосов | спросил Luke San Antonio Bialecki 10 MonEurope/Moscow2012-12-10T06:10:48+04:00Europe/Moscow12bEurope/MoscowMon, 10 Dec 2012 06:10:48 +0400 2012, 06:10:48

2 ответа


10

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

Вращение и ориентация различны, потому что первое описывает преобразование, а второе описывает состояние. Вращение - это , как объект попадает в ориентацию , а ориентация - это локальное вращающееся пространство объекта . Это может быть непосредственно связано с тем, как эти два представлены математически: матрица хранит преобразования из одного координатного пространства в другое (у вас это было правильно), а кватернион непосредственно описывает ориентацию. Поэтому матрица может описывать только , как объект попадает в ориентацию , посредством серии поворотов. Проблема с этим, однако, заключается в Gimbal Lock.

Gimbal lock демонстрирует трудность попадания объекта в ориентацию с использованием серии поворотов. Проблема возникает, когда по крайней мере две оси вращения выровнены:

Изображение предоставлено deepmesh3d.com
В левом изображении выше синяя и оранжевая оси делают одно и то же вращение! Это проблема, потому что это означает, что одна из трех степеней свободы потеряна, а дополнительные вращения с этой точки могут привести к неожиданным результатам. Использование кватернионов решает это, потому что применение кватерниона для преобразования ориентации объекта будет напрямую помещать объект в новую ориентацию (это лучший способ, я могу сказать это), вместо того, чтобы прервать преобразование в рулонные, подарочные и рысканные операции.

Теперь я на самом деле скептически отношусь к тому, что накопленные матрицы являются полным решением для этого, потому что накопленные матрицы (поэтому накапливающие вращения) именно то, что может вызвать проблему Gimbal Lock, в первую очередь. Правильный способ обработки преобразования кватернионом состоит в том, чтобы либо выполнить кватернионную мультипликацию в точке:

pTransformed = q * pAsQuaternion * qConjugate

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

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

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

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(45);

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

bookMatrix.RotateY(45);

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

glutil::MatrixStack bookMatrix;
bookMatrix.RotateY(45);
bookMatrix.RotateX(45);

Попробуйте! Начните книгу лицом к потолку снова. Измените его рыскание на 45 градусов, а затем поместите его на 45 градусов по глобальной оси X (бегите слева направо). Эта ориентация, которую вы ожидали с шагом 45 и рысканом 45 в локальном пространстве книги.

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

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

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

Надеюсь, что это поможет:)

ответил kevintodisco 10 MonEurope/Moscow2012-12-10T08:59:39+04:00Europe/Moscow12bEurope/MoscowMon, 10 Dec 2012 08:59:39 +0400 2012, 08:59:39
1

Матричные накопления могут фактически решить Gimbal lock. Накопив вращения, вы добавляете карданы, позволяя произвольное вращение. На диаграмме, представленной ktodisco, показана левая диаграмма. Матрица для этой ориентации может быть определена как:

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(90);
bookMatrix.RotateY(90);
bookMatrix.RotateZ(90);

Из-за поворота y gimbal X и Z карданы теперь заблокированы, поэтому мы потеряли одну степень движения. На этом этапе мы не имеем рыскания (локальный y, global z), используя эти три кардана. Но, добавив еще один карданный шар, я могу вращаться локально вокруг y:

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(90);
bookMatrix.RotateY(90);
bookMatrix.RotateZ(90);
bookMatrix.RotateY(90);

Для каждого нового рулона, высоты тона и рыскания просто добавьте еще один карданный шар, НАКОПИВШИЙ их в одну матрицу. Поэтому каждый раз, когда требуется другое локальное вращение, вращение создается и умножается на матрицу накопления. Как упоминается в главе, все еще есть проблемы, но карданный замок не является одним из них.

ответил Justin Ehrlich 2 AMpTue, 02 Apr 2013 03:37:50 +040037Tuesday 2013, 03:37:50

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132