The Matrix and Quaternions FAQ ============================== Version 1.4 26th December 1998 ------------------------------- This FAQ is maintained by "hexapod@netcom.com". Any additional suggestions or related questions are welcome. Just send E-mail to the above address. The latest copy of this FAQ can be found at the following web pages: ftp://ftp.netcom.com/pub/he/hexapod/index.html http://www.glue.umd.edu/~rsrodger Матрицы и кватернионы.
Вольный перевод с английского. Вступление I1: steve@mred.bgm.link.com Вступление ------------ I1. Важное замечание относящееся к OpenGL и этому документу Вопросы --------- ОСНОВЫ ====== Q1. Что такое матрицы? Q2. Что такое "порядок" матрицы? Q3. Как должен я представлять матрицы используя язык программирования C/C++? Q4. Какое преимущество даёт использование матриц? Q5. Как матрицы соотносятся с системами координат? АРИФМЕТИКА ========== Q6. Что такое единичная матрица? Q7. Что такое главная диагональ матрицы? Q8. Что такое транспонированная матрица? Q9. Как я должен складывать две матрицы друг с другом? Q10. Как я должен вычитать одну матрицу из другой? Q11. Как должен я перемножать матрицы? Q12. Как я должен возводить матрицу в квадрат и в степень? Q13. Как должен я умножать один или несколько векторов на матрицу? ОПРЕДЕЛИТЕЛИ И ОБРАТНЫЕ МАТРИЦЫ =============================== Q14. Что такое определитель (детерминант) матрицы? Q15. Как я могу вычислить определитель матрицы? Q16. Что такое изотропная и анизотропная матрицы? Q17. Что такое инвертированная матрица? Q18. Как могу я произвести инвертирование произвольной матрицы? Q19. Как я должен вычислять матрицу, обратную единичной? Q20. Как я должен вычислять матрицу, обратную матрице вращения? Q21. Как я должен инвертировать матрицу по правилу Крамера? Q22. Как я должен инвертировать 2х2 матрицу? Q23. Как я должен инвертировать 3х3 матрицу? Q24. Как я должен инвертировать матрицу 4х4? Q25. Как могу я вычислить обратную матрицу с помощью линейных уравнений? ТРАНСФОРМАЦИИ ============= Q26. Что такое матрица вращения? Q27. Как связана матрица вращения с координатной системой? Q28. Какую матрицу я должен применять для произведения вращения вокруг оси X? Q29. Какую матрицу я должен применять для произведения вращения вокруг оси Y? Q30. Какую матрицу я должен применять для произведения вращения вокруг оси Z? Q31. Что такое углы Эйлера? Q32. Что такое Yaw - рысканье, Roll - крен (бортовая качка) и Pitch - тангаж (килевая качка)? Q33. Как могу я комбинировать матрицы вращения? Q34. Что такое "Шарнирный замок" ("Gimbal lock")? Q35. Как правильно комбинировать матрицы вращения? Q36. Как могу я получить матрицу из Эйлеровых углов? Q37. Как должен я конвертировать матрицу вращения в углы Эйлера? Q38. Как могу я сгенерировать матрицу для произвольной оси и угла вращения? Q39. Как могу я сгенерировать матрицу вращения чтобы отобразить один вектор на другой? Q40. Как должен я употреблять матрицы для конвертирования одной системы координат в другую? Q41. Что такое матрица смещения (переноса)? Q42. Что такое матрица масштабирования? Q43. Что такое матрица сдвига? Q44. Как должен я производить линейную интерполяцию двух матриц? Q45. Как должен я производить кубическую интерполяцию четырех матриц? Q46. Как я могу отображать изменения в матрице? КВАТЕРНИОНЫ =========== Q47. Что такое кватернионы? Q48. Как работают кватернионы с трёхмерной анимацией? Q49. Как я должен вычислять сопряженный кватернион? Q50. Как я должен вычислять обратный кватернион? Q51. Как я должен вычислять величину кватерниона? Q52. Как я должен нормализовать кватернион? Q53. Как я могу перемножить два кватерниона друг с другом? Q54. Как должен я конвертировать кватернион в матрицу вращения? Q55. Как должен я конвертировать матрицу вращения в кватернион? Q56. Как должен я конвертировать ось вращения и угол в кватернион? Q57. Как должен я конвертировать кватернион в ось вращения и угол? Q58. Как должен я конвертировать сферические углы вращения в кватернион? Q59. Как должен я конвертировать кватернион в сферические углы вращения? Q60. Как должен я конвертировать Эйлеровы углы вращения в кватернион? Q61. Как должен я употреблять кватернионы для выполнения Вступление------------------------I1.Важное замечание относящееся к OpenGL и этому документуВ этом документе (как и в большинстве книг по математике), все матрицы выведены на стандартный математический манер. К сожалению, графические библиотеки, такие как IrisGL, OpenGL используют матрицы, в которых ряды и столбцы поменялись местами. Следовательно, в этом документе вы увидите, например, 4х4 матрицу перемещения, представленную как здесь: | 1 0 0 X | | | | 0 1 0 Y | M = | | | 0 0 1 Z | | | | 0 0 0 1 | Эту матрицу мог бы заполнить, например, такой код: M[0][1] = M[0][2] = M[0][3] = M[1][0] = M[1][2] = M[1][3] = M[2][0] = M[2][1] = M[2][3] = 0 ; M[0][0] = M[1][1] = M[2][2] = m[3][3] = 1 ; M[3][0] = X ; M[3][1] = Y ; M[3][2] = Z ; т.е матрица была бы сохранена в таком массиве: | M[0][0] M[1][0] M[2][0] M[3][0] | | | | M[0][1] M[1][1] M[2][1] M[3][1] | M = | | | M[0][2] M[1][2] M[2][2] M[3][2] | | | | M[0][3] M[1][3] M[2][3] M[3][3] | В OpenGL для хранения матриц употребляют одномерные массивы, но, к счастью, порядок упаковки тот же самый, что и для байтов в памяти - так, беря адрес pfMatrix и приведя его ко float* можно сразу передать его какой-либо функции OpenGL вроде glLoadMatrixf. В отрывках кода повсюду в этом документе для сохранения матриц используется одномерный массив. Порядок элементов массива, по сравнению с OpenGL изменён. Этот документ OpenGL | 0 1 2 3 | | 0 4 8 12 | | | | | | 4 5 6 7 | | 1 5 9 13 | M = | | M = | | | 8 9 10 11 | | 2 6 10 14 | | | | | | 12 13 14 15 | | 3 7 11 15 | Ответы на вопросы
Основы================== Q1. Что такое матрицы?
Матрицы - это двумерный массив числовых данных, где каждый ряд или столбец состоит из одного или более чисел. Над матрицами могут быть совершены различные арифметические операции, такие, как сложение, вычитание, умножение, деление. Размер матриц определяется в терминах числа рядов и столбцов. Матрица с M рядами и N столбцами определена как матрица MxN. Индивидуальный элемент матрицы обозначают, употребляя два индексных значения. Используя математическую нотацию, обычно назначают переменные 'i' (номер ряда) и 'j'(номер столбца). Например, в матрице 4х4 элементы индексируются так: | 00 10 20 30 | M = | 01 11 21 31 | | 02 12 22 32 | | 03 13 23 33 | Элемент в правом верхнем углу матрицы имеет индексы i = 0 и j = 3. Такой элемент обозначают так: M i,j = M 0,3 В компьютерной анимации наибольшее употребление имеют матрицы по 2, 3 или 4 ряда и столбца. Их обозначают соответственно как матрицы 2х2, 3х3 и 4х4. Матрицы 2х2 употребляются для совершения операций вращения, сдвига и других типов создания изображения. Универсальные NxN матрицы могут быть использованы для совершения процессов создания изображений, таких, как свертывание. Матрицы 3х3 употребляются для создания низкозатратной 3-х мерной анимации. Такие операции, как вращение и умножение могут быть совершены с этими матрицами, но перспективные преобразования могут быть выполнены, с использованием стандартных операций деления. Матрицы 4х4 употребляются для создания высококачественной трёхмерной анимации. Операции, такие, как умножение и создание перспективы могут быть совершены при помощи матричной математики. Q2. Что такое "порядок" матрицы?
"Порядок" матрицы - это другое название размерности матрицы. Говорят, что матрица с M рядами и N столбцами имеет порядок MxN. Q3. Как должен я представлять матрицы используя язык программирования C/C++?
Простейший способ определения матрицы в языке программирования C/C++ - использование ключевого слова typedef. Как 3х3 так и 4х4 матрицы могут быть определены таким путём: typedef float MATRIX3[9]; typedef float MATRIX4[16]; Поскольку каждый тип матриц имеет размерность 3х3 и 4х4, это требует соответственно 9 и 16 элементов. С первого взгляда употребление одномерного массива может показаться нелогичным. Более удобным может показаться употребление двумерного массива т.е: typedef float MATRIX3[3][3]; typedef float MATRIX4[4][4]; Однако употребление таких массивов очень часто ведёт к путанице. В математике сначала идут ряды (i), затем столбцы (j), т.е.: Mij В языке C/C++ такая матрица принимает вид: matrix[j][i] Кроме того, употребление двумерного массива уменьшает производительность процессора. Итак, более эффективно использование одномерного массива. Однако ещё остаются некоторые вопросы, требующие разъяснения. Как двумерную матрицу поместить в одномерный массив? Имеются два способа (сначала ряды/затем столбцы или сначала столбцы/затем ряды). Разница между этими двумя способами тонкая. Если распутать все циклы, тогда обнаружится маленькая разница в таких операциях, как матричное уиножение. В языке программирования C/C++ линейный порядок каждой матрицы следующий: mat[0] = M mat[3] = M 00 03 mat[12] = M mat[15] = M 30 33 | 0 1 2 3 | | | | 0 1 2 | | 4 5 6 7 | | | M = | | M = | 3 4 5 | | 8 9 10 11 | | | | | | 6 7 8 | | 12 13 14 15 | Q4. Какое преимущество даёт использование матриц?
Первый вопрос, который обычно задают об употреблении матриц в компьютерной анимации - это вопрос о том, почему они должны использоваться в первую очередь. Интуитивно может показаться, что потери времени в циклах и матричном умножении замедляют выполнение программы. Аргументы против этих предположений могут быть указаны. При употреблении регистров процессора во время обработки счётных циклов данные кэшируются с целью оптимизировать доступ к памяти . Преимущества также могут быть отмечены. Математический подход, определяющий алгоритмы 3-х мерной графики, позволяет предсказывать и планировать разработку 3-х мерных анимированных приложений. Такое математическое моделирование позволяет выполнять анимацию персонажей, анимацию по линии сплайна, инверсную кинематику. Однако, часто возникают возражения, что было бы быстрее просто перемножить каждую пару координат с коэффициентом вращения вокруг оси, чем совершать полное векторно - матричное умножение. То есть:
Аргументы за это такие, как ниже: Дана вершина V = (x, y, z), углы вращения (A, B и C) и смещение (D, E, F). Алгоритм преобразования такой: --------------------------- sx = sin(A) // Присваивание нужно делать только один раз cx = cos(A) sy = sin(B) cy = cos(B) sz = sin(C) cz = cos(C) x1 = x * cz + y * sz // Вращение каждой вершины y1 = y * cz - x * sz z1 = z x2 = x1 * cy + z1 * sy y2 = z1 z2 = z1 * cy - x1 * sy x3 = x2 y3 = y2 * cx + z1 * sx z3 = z2 * cx - x1 * sx xr = x3 + D // Перемещение каждой вершины yr = y3 + E zr = z3 + F --------------------------- Выполнение этого алгоритма требует таких затрат процессорного времени: Присваивание На каждую вершину ------------------------- ------------------------ 6 тригонометрических функций 6 операций присваивания 12 присваиваний 12 умножений 9 сложений ------------------------- ------------------------ Предположим теперь, что те же самые операции были совершены с помощью матричного умножения. С матрицей 4х4 затраты процессорного времени будут такими: Присваивание Изменение На каждую вершину Изменеие -------------------------- ------ ------------------------ ------ 6 тригонометрических функций 0 0 18 операторов присваивания +12 3 оператора присваивания -9 12 умножений +12 9 умножений -3 6 вычитаний +6 6 сложений -3 -------------------------- ------ ------------------------ ------ Сравнивая эти две таблицы может показаться, что употребление матриц требует дополнительных затрат процессорного времени, а именно, 12 умножений и 18 присваиваний. Однако, как бы это не казалось невероятным, происходит экономия процессорного времени благодаря сокращению затрат на повершинные операции. При матричном перемножении времени тратится меньше уже при преобразовании координат 4 вершин. Q5. Как матрицы соотносятся с системами координат?
Между каждой 3х3 или 4х4 матрицами вращения, перемещения, или сдвига и результирующей координатной системой существует простое соотношение. Первые три столбца матрицы определяют направление осей X, Y и Z соответственно. Если матрица 4х4 определена, как: | A B C D | M = | E F G H | | I J K L | | M N O P | Тогда векторы, задающие направление каждой из осей, определяются так: X-axis = [ A E I ] Y-axis = [ B F J ] Z-axis = [ C G K ] Арифметика==================Q6. Что такое единичная матрица?
Единичная матрица - та матрица, которая имеет равное число рядов и столбцов. Также все элементы, у которых i=j равны единице. Все остальные элементы - нули. Например, единичная 4х4 матрица такая: | 1 0 0 0 | M = | 0 1 0 0 | | 0 0 1 0 | | 0 0 0 1 | Q7. Что такое главная диагональ матрицы?
Главная диагональ матрицы - это набор элементов, у которых номер занимаемого ряда равен номеру занимаемого элементом столбца, т.е.: M где i=j ij В случае единичной матрицы только элементы главной диагонали имеют значение 1, в то время, как остальные имеют значение 0. Q8. Что такое транспонированная матрица?
Транспонированная матрица - это матрица, все элементы которой переставлены на противоположные, относительно главной диагонали, места. (То есть строки записаны в столбцы) Такая операция математически выражается так: M' = M ij ji Однако, такая операция возможна только если матрица имеет одинаковое число рядов и столбцов. Если матрица определена как: | 0.707 -0.866 | M = | | | 0.866 0.707 | Тогда транспонированная матрица эквивалентна такой: | 0.707 0.866 | T = | | | -0.866 0.707 | Если данная матрица - матрица вращения, тогда транспонирование гарантирует преобразование её в обратную матрицу. Q9. Как я должен складывать две матрицы друг с другом?
Правило сложения матриц такое: "прибавляй ряды и столбцы к рядам и столбцам" Математически это может быть выражено так: R = M + L ij ij ij Однако, обе матрицы должны иметь одну и ту же размерность. Например, если 3х3 матрицу M сложить с 3х3 матрицей L, тогда результат будет такой: R = M + L | A B C | | J K L | | | | | = | D E F | + | M N O | | | | | | G H I | | P Q R | | A+J B+K C+L | | | = | D+M E+N F+O | | | | G+P H+Q I+R | Q10. Как я должен вычитать одну матрицу из другой?
Правило вычитания двух матриц такое: "вычитай ряды и столбцы из рядов и столбцов". Математически это может быть выражено так: R = M - L ij ij ij Однако, обе матрицы должны иметь одну и ту же размерность. Например, если 3х3 матрица L вычитается из 3х3 матрицы M, тогда результат будет такой: R = M - L | A B C | | J K L | | | | | = | D E F | - | M N O | | | | | | G H I | | P Q R | | A-J B-K C-L | | | = | D-M E-N F-O | | | | G-P H-Q I-R | Q11. Как должен я перемножать матрицы?
Правило перемножения матриц такое: "умножай ряд на столбец и суммируй результат". Математически это может быть выражено так: n -- R = \ M x L ij / ij ji -- i=1 Если две перемножаемые матрицы имеют такой порядок: M = AxB и L = CxD тогда два значения - B и C - должны быть равны друг другу. Результирующая матрица тогда будет иметь порядок AxD. Таким образом, возможно, например, перемножение матриц Nх4 и 4хМ, но нельзя перемножить матрицы 4хN и Mх4. Например, если 4х4 матрица M определена как: | A B C D | M = | E F G H | | I J K L | | M N O P | а 4х2 матрица L определена как: | Q R | L = | S T | | U V | | W X | Тогда размер результирующей матрицы будет 4х2. Результирующая матрица определяется так: R = M x L | A B C D | | Q R | = | E F G H | x | S T | | I J K L | | U V | | M N O P | | W X | | AQ+BS+CU+DW AR+BT+CV+DX | = | EQ+FS+GU+HW ER+FT+GV+HX | | IQ+JS+KU+LW IR+JT+KV+LX | | MQ+NS+OU+PW MR+NT+OV+PX | Q12. Как я должен возводить матрицу в квадрат и в степень?
Матрица может быть возведена в квадрат или целую степень. Однако, имеется несколько ограничений. Для всех степеней матрица должна иметь одинаковое число рядов и столбцов. Например, M -1 - обратная матрица M 0 - генерирует единичную матрицу M 1 - не производит никаких действий с матрицей M 2 - возводит матрицу в квадрат M 3 - генерирует кубическую матрицу Возведение матрицы в степень, большую, чем один означает умножение матрицы на саму себя определённое число раз. Например, M 2 = M • M M 3 = M • M • M и т. д. При возведении единичной матрицы в любую степень всегда в результате получаем единичную матрицу, т.е.: I n = I Q13. Как должен я умножать один или несколько векторов на матрицу?
Лучший способ решить эту задачу - представить весь список векторов как единственную матрицу с векторами, записанными "в столбик" ("вектор-столбец"). Если N векторов нужно перемножить с матрицей 4х4, тогда их можно представить в виде единственной матрицы 4хN: Если матрица определена как: | A B C D | M = | E F G H | | I J K L | | M N O P | И список векторов такой: | x1 x2 x3 x4 x5| V = | y1 y2 y3 y4 y5| | z1 z2 z3 z4 z5| | 1 1 1 1 1| Обратите внимание, что добавлен дополнительный ряд, каждый элемент которого равен 1.0. Реально таких элементов не существует. Они добавлены только для того, чтобы совпал порядок матрицы и списка векторов. Затем совершается умножение как ниже: M . V = V' | A B C D | | x1 x2 x3 x4 x5 | | A•x1+B•y1+C•z1+D A•x2+B•y2+C•z2+D ... | | E F G H | • | y1 y2 y3 y4 y5 | = | E•x1+F•y1+G•z1+H E•x2+F•y2+G•z2+H ... | | I J K L | | z1 z2 y3 y4 z5 | | I•x1+J•y1+K•z1+L I•x2+J•y2+K•z2+L ... | | M N O P | | 1 1 1 1 1 | | M•x1+N•y1+O•z1+P M•x2+N•y2+O•z2+P ... | На каждый вектор в списке всего приходится 12 умножений, 16 сложений и 1 деление (для построения перспективы). Если известно, что данная матрица - не матрица вращения или перемещения, тогда операция деления может быть опущена. Определители и обратные матрицы=====================================Q14. Что такое определитель (детерминант) матрицы?
Определитель (детерминант) матрицы это действительное число, которое указывает, можно ли инвертировать матрицу, или нет. Если детерминант равен нулю, то матрицу нельзя инвертировать. Если определитель не ноль - то можно. В качестве примера рассмотрим матрицу, содержащую один-единственный элемент: M = [ 1 ]. Для матрицы такого размера детерминант просто равен этому элементу. Проинвертировать такую матрицу - значит просто найти обратную величину этого элемента: M -1 = [ 1 / M[0][0] ]Если единственный элемент матрицы не равен нулю, тогда (обращение) инвертирование возможно. В случае, если матрица единичная её обращением (инвертированием) будет 1/1 или 1.0. Однако, если значение единственного элемента такой матрицы равно нулю, тогда определитель тоже равен нулю. При попытке вычислить величину, обратную нулю, получаем бесконечность. Итак, инвертирование матрицы с нулевым детерминантом не определено. У единичной матрицы определитель всегда равен единице. Любая матрица, определитель которой равен 1.0, называется изотропной. Таким образом, все матрицы вращения изотропны, поскольку их детерминант равен 1.0. Это можно доказать так: | A B | | cos X -sin X | M = | | = | | | C D | | sin X cos X | D = AD - BC D = (cos X . cos X) - (-sin X . sin X) 2 2 D = (cos X ) + (sin X) 2 2 Но cos X + sin X = 1 Следовательно, D = 1 Q15. Как я могу вычислить определитель матрицы?
Определитель матрицы вычисляется по правилу Крамера. Для матрицы 2х2 определитель вычисляется так: | A B | M = | | | C D | D = AD - BC Для матриц 3х3 и 4х4 потребуются более сложные вычисления, по методу Крамера. Q16. Что такое изотропная и анизотропная матрицы?
Изотропная матрица эта та, у которой сумма квадратов всех рядов или столбцов равна единице. Все остальные матрицы считаются анизотропными. Когда 3х3 или 4х4 матрицы употребляются для вращения или масштабирования объекта, иногда необходимо вытянуть или уменьшить одну из осей. К примеру, при сейсмических исследованиях удобно удлинять Z-ось на 50 и более процентов, оставляя оси X и Y без изменений. Другой пример — "сжатие" и "вытягивание" персонажей анимации. Когда какой-либо объект "расплющивают на наковальне" желаемый эффект можно получить вытягивая его по сторонам и сжимая по вертикали. Подходящая для этого матрица может быть такой: | 2 0 0 0 | M = | 0 2 0 0 | | 0 0 0.5 0 | | 0 0 0 1 | Однако, тут появляются проблемы. Правильно производя трансформацию вершин, такая матрица вызывает неправильное наложение теней при употреблении нормалей. Из-за того, что трансформацию сцены выполняют посредством матричного умножения, данные как вершин, так и нормалей перемножаются с этой матрицей. Корректно трансформируя вершины, мы получаем головную боль с данными нормалей. После "сырого" перемножения, каждая нормаль больше не будет иметь единичную длину, и, следовательно, это затронет и другие вычисления, такие, как расчет теней и оттенков и отсечение невидимых граней. Q17. Что такое инвертированная матрица?
Пусть дана матрица M, тогда матрица, обратная этой (т. е. инвертированная), обозначаемая, как M -1, должна удовлетворять следующему выражению: -1 M • M = I где I - единичная матрица. Таким образом, перемножение матрицы с ей обратной, генерирует единичную матрицу. Однако, чтобы была возможна инверсия, исходная матрица должна удовлетворять некоторым требованиям. Требования такие: число рядов исходной матрицы должно быть равно числу столбцов, и определитель матрицы не должен быть равен нулю. Вычисление матрицы, обратной данной - часто встречающаяся задача в инверсной кинематике, анимации по линиям сплайнов. Q18. Как могу я произвести инвертирование произвольной матрицы?
В зависимости от размера матрицы её инвертирование может быть как очень простой, так и чрезвычайно сложной операцией. Например, чтобы инвертировать матрицу 1х1 надо просто найти величину, обратную единственному элементу матрицы: т. е. если M = | x | Тогда обращение определяется, как: -1 | 1 | M = | - | | x | Что касается матриц порядка 2х2 и выше, их обращение может быть достигнуто использованием правила Крамера или решением ряда систем уравнений. Однако, в некоторых случаях, таких, как с единичной матрицей или матрицей вращения, обратная матрица уже известна, или может быть определена с помощью транспонирования (перестановки). Q19. Как я должен вычислять матрицу, обратную единичной?
Тут и вычислять нечего. Матрица, обратная единичной - это единичная матрица. Т. е. -1 I . I = I Всякая единичная матрица имеет определитель равный единице. Q20. Как я должен вычислять матрицу, обратную матрице вращения?
Поскольку матрица вращения всегда имеет определитель равный +1, вычисление ей обратной эквивалентно вычислению транспонированной матрицы. Кроме того, если углы вращения известны, тогда эти углы могут быть заменены на отрицательные и использованы для вычисления новой матрицы вращения. Q21. Как я должен инвертировать матрицу по правилу Крамера?
Возьмём матрицу 3х3: | A B C | | | M = | D E F | | | | G H I | Её определитель вычисляется так: n --- \ i опр. M = / M * подматр. M * -1 --- 0,i 0,i i=1 где подматрица i j сформирована из всех рядов и столбцов матрицы M, за исключением ряда i и столбца j. Подматрица i j может вызываться рекурсивно. Если определитель не нуль - тогда обратная матрица существует. В этом случае значение каждого элемента матрицы вычисляется так: -1 1 i+j M = ------ * опр. подматр. M * -1 j,i опр. M i,j Q22. Как я должен инвертировать 2х2 матрицу?
Для матрицы 2х2 вычисления немного труднее. Если матрица определена как: | A B | M = | | | C D | Тогда её определитель вычисляется так: опр. = AD - BC И обращение производят следующим образом: -1 1 | D -B | M = --- | | опр. | -C A | Это может быть проверено с помощью правила Крамера. Дана матрица M: | A B | M = | | | C D | Тогда её определитель есть: 0 1 опр. = M подматр. M * -1 + M * подматр. M * -1 0,0 0,0 0,1 0,1 <=> M * M * 1 + M * M * -1 0,0 1,1 0,1 1,0 <=> A * D + B * C * -1 <=> AD + BC * -1 <=> AD - BC ============== И обращение производится так: -1 0+0 -1 M = опр. подматр. * -1 <=> M = M * 1 <=> D 0,0 0,0 0,0 1,1 -1 1+0 -1 M = опр. подматр. * -1 <=> M = M * -1 <=> C * -1 0,1 1,0 0,1 1,0 -1 0+1 -1 M = опр. подматр. * -1 <=> M = M * -1 <=> B * -1 1,0 0,1 1,0 0,1 -1 1+1 -1 M = опр. подматр. * -1 <=> M = M * 1 <=> A 1,1 1,1 1,1 0,0 Тогда обратная матрица будет такой: -1 1 | D -C | M = --- | | опр.| -B A | при условии, что её определитель не равен нулю. Q23. Как я должен инвертировать 3х3 матрицу?
Для матриц порядка 3х3 и выше обратная матрица может быть вычислена с помощью правила Крамера или решением системы линейных уравнений. Если применить правило Крамера к матрице M: | A B C | M = | D E F | | G H I | тогда определитель вычисляется так: опр. M = A * (EI - HF) - B * (DI - GF) + C * (DH - GE) Если определитель не равен нулю, тогда обратная матрица вычисляется так: -1 1 | EI-FH -(BI-HC) BF-EC | M = ----- • | -(DI-FG) AI-GC -(AF-DC) | опр. M | DH-GE -(AH-GB) AE-BD | Это может быть выполнено с помощью пары 'C' - функций: --------------------------------- VFLOAT m3_det( MATRIX3 mat ) { VFLOAT det; det = mat[0] * ( mat[4]*mat[8] - mat[7]*mat[5] ) - mat[1] * ( mat[3]*mat[8] - mat[6]*mat[5] ) + mat[2] * ( mat[3]*mat[7] - mat[6]*mat[4] ); return( det ); } ---------------------------------- void m3_inverse( MATRIX3 mr, MATRIX3 ma ) { VFLOAT det = m3_det( ma ); if ( fabs( det ) < 0.0005 ) { m3_identity( ma ); return; } mr[0] = ma[4]*ma[8] - ma[5]*ma[7] / det; mr[1] = -( ma[1]*ma[8] - ma[7]*ma[2] ) / det; mr[2] = ma[1]*ma[5] - ma[4]*ma[2] / det; mr[3] = -( ma[3]*ma[8] - ma[5]*ma[6] ) / det; mr[4] = ma[0]*ma[8] - ma[6]*ma[2] / det; mr[5] = -( ma[0]*ma[5] - ma[3]*ma[2] ) / det; mr[6] = ma[3]*ma[7] - ma[6]*ma[4] / det; mr[7] = -( ma[0]*ma[7] - ma[6]*ma[1] ) / det; mr[8] = ma[0]*ma[4] - ma[1]*ma[3] / det; } --------------------------------- Q24. Как я должен инвертировать матрицу 4х4?
Так же, как и матрицу 3х3, или применив правило Крамера, или решив систему линейных уравнений. Лучше всего использовать существующие C-функции, предназначенные для вычисления определителей и обращения 3х3 матриц. Для того, чтобы произвести вычисления по правилу Крамера, сначала необходимо определить подматрицы. Это делает следующая функция: -------------------------- void m4_submat( MATRIX4 mr, MATRIX3 mb, int i, int j ) { int ti, tj, idst, jdst; for ( ti = 0; ti < 4; ti++ ) { if ( ti < i ) idst = ti; else if ( ti > i ) idst = ti-1; for ( tj = 0; tj < 4; tj++ ) { if ( tj < j ) jdst = tj; else if ( tj > j ) jdst = tj-1; if ( ti != i && tj != j ) mb[idst*3 + jdst] = mr[ti*4 + tj ]; } } } -------------------------- Определитель матрицы 4х4 может быть вычислен так: -------------------------- VFLOAT m4_det( MATRIX4 mr ) { VFLOAT det, result = 0, i = 1; MATRIX3 msub3; int n; for ( n = 0; n < 4; n++, i *= -1 ) { m4_submat( mr, msub3, 0, n ); det = m3_det( msub3 ); result += mr[n] * det * i; } return( result ); } -------------------------- И обратная матрица может быть вычислена как здесь: -------------------------- int m4_inverse( MATRIX4 mr, MATRIX4 ma ) { VFLOAT mdet = m4_det( ma ); MATRIX3 mtemp; int i, j, sign; if ( fabs( mdet ) < 0.0005 ) return( 0 ); for ( i = 0; i < 4; i++ ) for ( j = 0; j < 4; j++ ) { sign = 1 - ( (i +j) % 2 ) * 2; m4_submat( ma, mtemp, i, j ); mr[i+j*4] = ( m3_det( mtemp ) * sign ) / mdet; } return( 1 ); } -------------------------- Владея функциями, которые могут вычислять матрицы, обратные любым 4х4 матрицам вы обладаете чрезвычайно полезным инструментом, с помощью которого можно найти базовые матрицы для сплайнов, матрицы обратного вращения и преобразовывать системы координат. Q25. Как могу я вычислить обратную матрицу с помощью линейных уравнений?
Если имеется такая матрица M: | A B C | M = | D E F | | G H I | тогда обратная ей пусть будет такой: | P Q R | M' = | S T U | | V W X | и верны следующие выражения: -1 M • M = I | A B C | | P Q R | | 1 0 0 | | D E F | • | S T U | = | 0 1 0 | | G H I | | V W X | | 0 0 1 | Обратная матрица тогда может быть вычислена решением следующих систем уравнений: | AP + BS + CV | | 1 | Столбец 0 (X) | DP + ES + FV | = | 0 | | GP + HS + IV | | 0 | | AQ + BT + CW | | 0 | Столбец 1 (Y) | DQ + ET + FW | = | 1 | | GQ + HT + IW | | 0 | | AR + BU + CX | | 0 | Столбец 2 (Z) | DR + EU + FX | = | 0 | | GR + HU + IX | | 1 | Трансформации=======================Q26. Что такое матрица вращения?
Матрица вращения употребляется для вращения набора точек в пределах координатной системы. В то время, как каждая точка получает новые координаты, относительные расстояния между ними не меняются. Все вращения определяются с помощью тригонометрических функций - синусов и косинусов. Для двумерной системы координат матрица вращения такая: | cos(A) -sin(A) | | | | sin(A) cos(A) | Если в такой матрице установить угол A = 0, тогда получим единичную матрицу. | 1 0 | I = | | | 0 1 | Если необходимо произвести вращение на +90 градусов, тогда матрица должна быть такой: | 0 -1 | M = | | | 1 0 |
Если же нужно произвести вращение на -90 градусов, тогда матрица должна быть такой: | 0 1 | M = | | | -1 0 | Заменяя положительный угол вращения на точно такой же отрицательный, мы производим транспонирование матрицы. Если одну матрицу вращения перемножить с другой, полученной из первой транспонированием, результатом будет единичная матрица. Q27. Как связана матрица вращения с координатной системой?
Матрицы вращения соотносятся с системой координат так. По принятому в математике соглашению, положительным считается угол, произведённый по движению часовой стрелки, если наблюдатель смотрит из начала координат вдоль положительного направления оси вращения. Применяя это правило, можно вывести три Декартовы матрицы вращения. Рассмотрим правостороннюю систему координат. Для каждой оси вращения, смотря от начала системы координат, вдоль положительного направления выбранной оси, получим три таких вида: +----------------------------------------+ | | | X-ось Y-ось Z-ось | | | | | | ^ Y ^ Z Y ^ | | | | | | | | | | | | | | | | | | | | | | O----> Z O----> X X <----O | | | +----------------------------------------+ Поскольку положительным углом вращения считается угол произведённый по часовой стрелке, то возможно произвести отображение координат для любого вращения. Для простоты, будем считать, что угол вращения равен +90 градусам: Начнём с оси X: ( 0, 1, 0 ) -> ( 0, 0, 1 ) ( 0, 0, 1 ) -> ( 0,-1, 0 ) ( 0,-1, 0 ) -> ( 0, 0,-1 ) ( 0, 0,-1 ) -> ( 0, 1, 0 ) Это может быть упрощено: X' = X Y' = -Z Z' = Y И затем преобразовано в матрицу: | 1 0 0 | Rx = | 0 cos A -sin A | | 0 sin A cos A | Сделаем то же самое для оси Y: ( 0, 0, 1) -> ( 1,0, 0) ( 1, 0, 0) -> ( 0,0,-1) ( 0, 0,-1) -> (-1,0, 0) (-1, 0, 0) -> ( 0,0, 1) Упрощая получим: X' = Z Y' = Y Z' = -X Преобразуем в матрицу: | cos A 0 sin A | Ry = | 0 1 0 | | -sin A 0 cos A | И, наконец, для оси Z: ( 0, 1, 0 ) -> ( -1, 0, 0 ) (-1, 0, 0 ) -> ( 0, -1, 0 ) ( 0,-1, 0 ) -> ( 1, 0, 0 ) ( 1, 0, 0 ) -> ( 0, 1, 0 ) Упрощаем: X' = -Y Y' = X Z' = Z Преобразовываем в матрицу: | cos A -sin A 0 | Rz = | sin A cos A 0 | | 0 0 1 | Это три основные матрицы вращения, используемые в OpenGL. Q28. Какую матрицу я должен применять для произведения вращения вокруг оси X?
Используйте такую матрицу: | 1 0 0 0 | M = | 0 cos(A) -sin(A) 0 | | 0 sin(A) cos(A) 0 | | 0 0 0 1 | Q29. Какую матрицу я должен применять для произведения вращения вокруг оси Y?
Используйте такую матрицу: | cos(A) 0 sin(A) 0 | M = | 0 1 0 0 | | -sin(A) 0 cos(A) 0 | | 0 0 0 1 | Q30. Какую матрицу я должен применять для произведения вращения вокруг оси Z?
Используйте такую матрицу: | cos(A) -sin(A) 0 0 | M = | sin(A) cos(A) 0 0 | | 0 0 1 0 | | 0 0 0 1 | Q31. Что такое углы Эйлера?
Эйлеровыми углами называют множество углов, заданных вокруг каждой из X, Y и Z - осей вращения. Они определены в векторном формате (напр. |x y z|) и могут быть сохранены как вектор (т.е одномерный массив). Например, набор | 0 0 0 | всегда генерирует единичную матрицу. Другие углы представлены так: | 90 0 0 | вращение на +90 градусов вокруг оси X, | 0 90 0 | вращение на +90 градусов вокруг оси Y и | 0 0 90 | вращение на +90 градусов вокруг оси Z. Каждый из Эйлеровых углов может быть представлен в памяти как векторная структура данных. Q32. Что такое Yaw - рысканье, Roll - крен (бортовая качка) и Pitch - тангаж (килевая качка)?
Рысканье, крен и тангаж - авиационные термины, обозначающие вращения в Декартовой системе координат (по Эйлеровым углам), относительно локальной системы координат самолёта. Вообразите, что вы видите впереди и ниже себя самолёт. Ось Z проходит от хвоста к носу самолёта. Ось X идёт от конца левого крыла к концу правого. Ось Y направлена снизу прямо вверх. Тогда тангаж - это вращение вокруг оси X, рысканье - вращение вокруг оси Y и крен - вращение вокруг оси Z. Q33. Как могу я комбинировать матрицы вращения?
Матрицы вращения комбинируются друг с другом посредством матричного умножения. Для получения правильного результата ,при перемножении нескольких матриц, порядок умножения очень важен. Q34. Что такое "Шарнирный замок" ("Gimbal lock")?
Т. н. "Шарнирный замок" - это название проблемы, возникающей при использовании Эйлеровых углов. Из-за того, что конечный результат серии вращений зависит от порядка промежуточных вращений, иногда случается, что вращение вокруг одной оси отображается на вращение вокруг другой оси. Даже хуже, может быть невозможно вращать объект вокруг желаемой оси. Вот это и есть "Шарнирный замок". Например, предположим, что объект последовательно вращают вокруг Z (на небольшой угол), Y, X - осей, и угол вращения вокруг оси Y равен 90 градусам. В этом случае вращение вокруг оси Z происходит первым и, поэтому, корректно. Вращение вокруг оси Y тоже совершается корректно. Однако после вращения вокруг оси Y на 90 градусов, ось X отображается на ось Z. Таким образом, совершая вращение вокруг (относительной) X-оси мы фактически вращаем объект вокруг (абсолютной) оси Z. Единственное решение этой проблемы - использование кватернионов. Q35. Как правильно комбинировать матрицы вращения?
На самом деле не существует "правильного способа" комбинации матриц. Однако, чтобы быть в состоянии предсказать результат комбинации матриц, некоторая организация необходима. Простейший способ вращения объекта - это перемножение матриц в таком порядке: M = X•Y•Z где M - конечная матрица, и X, Y, Z - промежуточные матрицы. Они определяют вращение вокруг оси X (тангаж или килевая качка), затем вокруг оси Y (рысканье), и, наконец, вокруг оси Z (крен или бортовая качка). Однако, всякий раз, когда вид из камеры пересчитывается, тогда порядок и углы вращения полностью изменяются Например, если вы стоите прямо и поворачиваетесь налево, то всё вокруг в вашем поле зрения поворачивается вокруг вас направо. Однако, кто-нибудь, стоящий лицом к лицу с вами может сказать, что это вы повернулись направо. Таким образом, вид из камеры моделируется в таком порядке: M = —X • —Y • —Z Обратная (или транспонированная) матрица необходима, если камера представлена как другой объект. Q36. Как могу я получить матрицу из Эйлеровых углов?
На первый взгляд, самый естественный метод получения матрицы вращения из набора Эйлеровых углов - это сгенерировать каждую матрицу индивидуально и перемножить три полученные матрицы друг с другом, т. е.: m3_rotx( mat_x, vec -> angle_x ); m3_roty( mat_y, vec -> angle_y ); m3_rotz( mat_z, vec -> angle_z ); m3_mult( mat_tmp, mat_z, mat_y ); m3_mult( mat_final, mat_tmp, mat_x ); Всё это может быть скомпоновано в одной функции, напр.: m3_fromeuler( MATRIX *mat_final, VECTOR3 *euler ) Однако, выполнение такой последовательности требует больших затрат процессорного времени. Принимая во внимание, что каждая 4х4 матрица вращения гарантированно имеет 10 элементов, значение которых равно нулю, 2 элемента, равные единице, и 4 элемента, имеющие произвольные значения, окажется, что свыше 75% арифметических операций, совершаемых при перемножении матриц, совершенно не нужны. (Не считая операций присваивания.) При выполнении свыше 75% всех матричных операций, в результате получаем или ноль или единицу. Должен быть найден более эффективный способ. К счастью, такой способ, позволяющий определить результирующую матрицу, существует. Если все три матрицы объединить на алгебраический манер, то получим следующее выражение: M = X•Y•Z где Выводя матрицы вращения в алгебраическом формате, получим: | 1 0 0 | X = | 0 A -B | | 0 B A | | C 0 -D | Y = | 0 1 0 | | D 0 C | | E -F 0 | Z = | F E 0 | | 0 0 1 | где
Тогда выражение: M = X•Y•Z Может быть разбито на два матричных умножения: M' = X•Y M = M'•Z Сначала вычислим матрицу M': M' = X•Y | 1 0 0 | | C 0 -D | M' = | 0 A -B | • | 0 1 0 | | 0 B A | | D 0 C | | 1•C + 0•0 + 0•D 1•0 + 0•1 + 0•0 1•-D + 0•0 + 0•C | M' = | 0•C + A•0 + -B•D 0•0 + A•1 + -B•0 0•-D + A•0 + -B•C | | 0•C + B•0 + A•D 0•0 + B•1 + A•0 0•-D + B•0 + A•C | Упрощение M' даёт: | C 0 -D | M' = | -B•D A -B•C | | A•D B A•C | Вычисление M даёт: M = M'•Z | C 0 -D | | E -F 0 | M = | -BD A -BC | • | F E 0 | | AD B AC | | 0 0 1 | | C•E + 0•F + -D•0 C•-F + 0•E + -D•0 C•0 + 0•0 + -D•1 | M = | -BD•E + A•F + -BC•0 -BD•-F + A•E + -BC•0 -BD•0 + A•0 + -BC•1 | | AD•E + B•F + AC•0 AD•-F + B•E + AC•0 AD•0 + 0•0 + AC•1 | Упрощение M даёт матрицу 3х3: | CE -CF -D | M = | -BDE+AF -BDF+AE -BC | | ADE+BF -ADF+BE AC | Это и есть результирующая матрица вращения. В виде матрицы 4х4 это будет: | CE -CF -D 0 | M = | -BDE+AF BDF+AE -BC 0 | | ADE+BF -ADF+BE AC 0 | | 0 0 0 1 | Сначала вычисляются значения A, B, C, D, E и F. Затем значения BD и AD, поскольку они встречаются больше, чем один раз. Таким образом, конечный алгоритм будет таким: ----------------------- A = cos(angle_x); B = sin(angle_x); C = cos(angle_y); D = sin(angle_y); E = cos(angle_z); F = sin(angle_z); AD = A * D; BD = B * D; mat[0] = C * E; mat[1] = -C * F; mat[2] = -D; mat[4] = -BD * E + A * F; mat[5] = BD * F + A * E; mat[6] = -B * C; mat[8] = AD * E + B * F; mat[9] = -AD * F + B * E; mat[10] = A * C; mat[3] = mat[7] = mat[11] = mat[12] = mat[13] = mat[14] = 0; mat[15] = 1; ----------------------- При использовании обычного матричного умножения, количество арифметических операций может достигать 128 умножений, 96 сложений и 80 присваиваний. При использовании же оптимизированного алгоритма требуется всего только 12 умножений, 6 вычитаний и 18 присваиваний. Итак, совершенно очевидно, что, используя оптимизированный алгоритм, мы получаем 10 - кратное увеличение производительности! Q37. Как должен я конвертировать матрицу вращения в углы Эйлера?
Эта операция прямо противоположна вышеизложенной. Предположим, что дана такая матрица вращения: | CE -CF -D 0 | M = | -BDE+AF BDF+AE -BC 0 | | ADE+BF -ADF+BE AC 0 | | 0 0 0 1 | где
Используя структуру данных языка C для матрицы 4х4, получим такие индексы элементов массива: | 0 1 2 3 | M = | 4 5 6 7 | | 8 9 10 11 | | 12 13 14 15 | Сравнивая эти две таблицы, можно увидеть, что элемент [2] массива имеет значение -D или -sin(Y). Следовательно, угол вращения вокруг оси X может быть вычислен вызовом функции asin(-D). Передав результат вычисления арксинуса функции cos(), получим значение C. Если C - не ноль, тогда угол вращения вокруг каждой из X и Z осей, может быть выведен из значений третьего столбца и первого ряда соответственно. Это можно сделать так: X-ось: M[6] = -BC M[10] = AC Z-ось: M[0] = CE M[1] = -CF Сами углы могут быть получены делением каждой пары значений на C с последующей передачей результатов функции atan(). Если значение C равно нулю, тогда изложенные выше вычисления невозможны. В этом случае угол вращения вокруг оси Y равен или -90 или +90 градусам, а D имеет значение или 1 или -1. Здесь имеет место т. н. "Шарнирный замок" ("Gimbal Lock"). Вращение вокруг осей Х и Z отображается как вращение вокруг одной и той же оси. Это можно увидеть, вычисляя оси вращения. | 0•E -0•F 1 0 | M = | -B•1•E+AF B•1•F+AE -B•0 0 | | A•1•E+BF -A•1•F+BE A•0 0 | | 0 0 0 1 | Дальнейшие вычисления дают: | 0 0 1 0 | M = | -BE+AF BF+AE 0 0 | | AE+BF -AF+BE 0 0 | | 0 0 0 1 | И после перестановки: | 0 0 1 0 | M = | -BE+AF AE+BF 0 0 | | AE+BF BE-AF 0 0 | | 0 0 0 1 | Тогда можно увидеть, что на самом деле матрица имеет такую форму: | 0 0 -1 0 | M = | -V W 0 0 | | W V 0 0 | | 0 0 0 1 | Где Эти два значения можно рассматривать, как синус и косинус углов вращения вокруг единственной оси. В окончательном виде алгоритм будет таким: ----------------------------------- angle_y = D = -asin( mat[2]); /* Вычисления угла вращения вокруг оси Y */ C = cos( angle_y ); angle_y *= RADIANS; if ( fabs( C ) > 0.005 ) /* "Шарнирный замок" (Gimball lock)? */ { trx = mat[10] / C; /* Если нет, то получаем угол вращения вокруг оси X */ try = -mat[6] / C; angle_x = atan2( try, trx ) * RADIANS; trx = mat[0] / C; /* Получаем угол вращения вокруг оси Z */ try = -mat[1] / C; angle_z = atan2( try, trx ) * RADIANS; } else /* Имеет место "Шарнирный замок" (Gimball lock) */ { angle_x = 0; /* Угол вращения вокруг оси X приравниваем к нулю */ trx = mat[5]; /* И вычисляем угол вращения вокруг оси Z */ try = mat[4]; angle_z = atan2( try, trx ) * RADIANS; } /* Ранжируем найденные углы в диапазон от 0 до 360 градусов */ angle_x = clamp( angle_x, 0, 360 ); angle_y = clamp( angle_y, 0, 360 ); angle_z = clamp( angle_z, 0, 360 ); ----------------------------------- Q38. Как могу я сгенерировать матрицу для произвольной оси и угла вращения?
Единственный способ сгенерировать матрицу произвольного угла и оси вращения - использовать математику кватернионов. Детальный ответ на этот вопрос дан ниже [Q54. Как должен я конвертировать кватернион в матрицу вращения?]. Q39. Как могу я сгенерировать матрицу вращения, чтобы отобразить один вектор на другой?
При разработке программ с анимацией, постоянно возникает необходимость отобразить один направляющий вектор на другой. Вообразите два радиус - вектора единичной длины. Тогда всевозможные вращения этих векторов образуют единичную сферу. Теоретически, имеется бесчисленное множество осей и углов вращения, отображающих один вектор на другой. Все эти оси лежат в одной плоскости, все точки которой имеют равное расстояние от обоих векторов. Но только одно решение имеет практический интерес. Это кратчайшее угловое расстояние между векторами. Ось вращения находим, вычисляя векторное произведение заданных векторов: Vaxis = Vs x Vf Угол вращения вычисляется с помощью скалярного произведения векторов: -1 Vangle = cos ( Vs . Vf ) На практике решение этой задачи используют для нахождения кратчайшего пути между двумя пунктами на поверхности Земли. В этом случае каждый из пунктов считается лежащим на концах радиус-векторов. Поскольку Земля имеет сферическую форму, искомый путь есть кратчайшее угловое расстояние между двумя этими пунктами. Q40. Как должен я употреблять матрицы для конвертирования одной системы координат в другую?
Эта проблема решается примерно так же, как предыдущая. Требуется преобразовать одну координатную систему в другую. Однако, вместо того, чтобы просто пытаться отобразить одну координатную ось на другую, необходимо добиться соответствия всех трёх осей. Следовательно, обе координатные системы представлены в виде матриц 3х3 или 4х4. Таким образом, проблема состоит в нахождении матрицы вращения, которая преобразует одну матрицу в другую. Математически это может быть выражено так: Mfinal = Mrot • Morig где Цель состоит в нахождении матрицы Mrot. Это может быть достигнуто перестановкой уравнения: -1 Mfinal • Morig = Mrot -1 Mrot = Mfinal • Morig Таким образом, нужная матрица вращения может быть найдена обращением матрицы исходной системы координат и последующим перемножением этой матрицы с финальной матрицей. Для проверки рассмотрим случаи, в которых или исходная или финальная матрица - единичная матрица. В каждом из этих случаев искомая матрица вращения должна совпадать соответственно с финальной и с инвертированной финальной матрицей. Вычисленная матрица вращения может быть конвертирована в кватернион. Q41. Что такое матрица смещения (переноса)?
Матрица смещения используется для позиционирования объекта в трёхмерном пространстве, без какого-либо вращения. Операция смещения в матричном исполнении возможна только с матрицей 4х4. Если смещение определено вектором [ X Y Z ], тогда матрица 4х4, выполняющая смещение, такая: | 1 0 0 X | | | | 0 1 0 Y | M = | | | 0 0 1 Z | | | | 0 0 0 1 | Если вектор смещения - нулевой ( [0 0 0] ), тогда матрица не производит никакого действия. Q42. Что такое матрица масштабирования?
Матрица масштабирования используется для уменьшения или увеличения 3-х мерной модели. Если масштабирующий вектор определён, как [X Y Z] тогда матрица масштабирования такая: | X 0 0 0 | | | | 0 Y 0 0 | M = | | | 0 0 Z 0 | | | | 0 0 0 1 | Если масштабирующий вектор определён, как [1 1 1], тогда генерируется единичная матрица, и никаких изменений не происходит. Q43. Что такое матрица сдвига?
Матрица сдвига используется для наклона 3-х мерных моделей в сторону. К примеру, для получения курсивного шрифта необходимо наклонить направо каждый отдельный символ шрифта (глиф). Имея три направления по осям XYZ можно произвести шесть операций сдвига:
# сдвиг X вдоль Y Все эти операции могут быть скомбинированы в одну-единственную матрицу: | 1 Syx Szx 0 | | | | Sxy 1 Szy 0 | M = | | | Sxz Syz 1 0 | | | | 0 0 0 1 | в которой Sij выполняет сдвиг I вдоль J. Таким образом, Sxy сдвигает X вдоль Y. Согласно теории, вращение в трёхмерном пространстве можно рассматривать как комбинацию сдвигов в шести направлениях. Q44. Как должен я производить линейную интерполяцию двух матриц?
Пусть даны две матрицы вращения, проблема состоит в нахождении способа определения промежуточных позиций, заданных параметрической переменной t, причём t задана в диапазоне от 0.0 до 1.0. Это может быть достигнуто путём конвертирования двух матриц или в Эйлеровы углы, или в сферические углы вращения (с помощью кватернионов) и вектора сдвига.
Интерполяция между этими двумя векторами может быть совершена с помощью стандартного уравнения линейной интерполяции: Vr = Va + t • (Vb - Va ) где Это уравнение может применяться как с векторами вращения, так и с векторами переноса. После определения результирующего вектора, он может быть конвертирован в искомую промежуточную матрицу. Q45. Как должен я производить кубическую интерполяцию четырех матриц?
Пусть даны четыре матрицы вращения или перемещения, проблема состоит в нахождении способа определения промежуточных позиций, заданных переменным параметром t. Это может быть достигнуто использованием кубической интерполяции. Как и в случае с линейной интерполяцией, четыре матрицы конвертируются в соответствующие им векторы перемещения и вращения. (Как и прежде, или при помощи Эйлеровых углов, или сферических углов вращения). Каждый комплект из четырёх векторов затем конвертируется в единственный вектор G. При помощи сплайновой математики, этот вектор преобразуется в M-матрицу интерполяции. Если вектор G определён как: | x1 x2 x3 x4 | G = | y1 y2 y3 y4 | | z1 z2 z3 z4 | тогда перемножение с базовой матрицей: | -4.5 9.0 -5.5 1.0 | Mb = | 13.5 -22.5 9.0 0.0 | | -13.5 18.0 -4.5 0.0 | | 4.5 -4.5 1.0 0.0 | сгенерирует 3х4 матрицу интерполяции Mi: Mi = G • Mb Это может быть выполнено при помощи стандартного матрично-векторного перемножения. Интерполяция тогда может совершаться с помощью параметрической переменной t: R = Mi • t |t^3| | xr | | A B C D | |t^2| | yr | = | E F G H | • |t | | zr | | I J K L | |1 | Результирующий вектор затем может быть конвертирован в матрицу вращения или смещения. Следует обратить внимание на то, что полученный путь может быть довольно извилист. Это нормально, поскольку алгоритм пытается найти кратчайшую сумму вращений между всеми четырьмя векторами. Из двух методов сферические углы вращения обычно обеспечивают более плавную интерполяцию. Q46. Как я могу отображать изменения в матрице?
При создании трёхмерных анимированных приложений, удобно отображать изменения в матрице параллельно анимации. Однако, отображение матрицы, как массива числовых значений не обеспечивает достаточной наглядности. Альтернатива выводу числовых данных - использование различных диаграмм и графиков. Подобно графическому компенсатору в стерео, матрица вращения может быть отображена в качестве графика. Каждый элемент матрицы выводится как индивидуальный столбец диаграммы в диапазоне от -1 до +1. Матрица 3х3 могла бы выглядеть примерно так: +--+ +--+ +--+ |##| | | | | +--+ +--+ +--+ | | | | | | +--+ +--+ +--+ +--+ +--+ +--+ | | |##| | | +--+ +--+ +--+ | | | | | | +--+ +--+ +--+ +--+ +--+ +--+ | | | | |##| +--+ +--+ +--+ | | | | | | +--+ +--+ +--+ В этом случае, матрица вращения - единичная матрица, поскольку каждый элемент главной диагонали равен +1, а все остальные элементы - нули. Для большей наглядности, отрицательные параметры могут быть выведены в другом цвете, нежели положительные. Кватернионы=======================Q47. Что такое кватернионы?
Кватернионы расширяют понятие вращения в трёх измерениях на вращение в четырёх измерениях. Они разрешают проблему т. н. В действительности они могут считаться дополнением к углам вращения в сферических координатах, т. е. широте, долготе и угла вращения. Кватернионы определяются четырьмя действительными числами [x y z w]. Они вычисляются из комбинации трёх координат, оси и угла вращения. Q48. Как работают кватернионы с трёхмерной анимацией?
Как ранее отмечено, Эйлеровы углы имеют недостаток из-за подверженности "Gimbal-lock", когда попытка последовательного вращения объекта вокруг осей в заданном порядке терпит неудачу. Кватернионы решают эту проблему. Вместо того, чтобы задавать вращение объекта как серию последовательных вращений, кватернионы позволяют программисту вращать объект вокруг произвольной оси на произвольный угол. Вращение по-прежнему совершается с помощью матриц. Однако, вместо того, чтобы перемножать матрицы, кватернионы изображают перемноженные между собой оси вращения. Результирующий кватернион затем конвертируется в желаемую матрицу вращения. Благодаря тому, что ось вращения определена как единичный вектор, это может быть вычисленно с помощью векторной алгебры или сферических координат (т.е. Широты/Долготы). Кватернионы предоставляют другие преимущества, так как они могут быть интерполированы. Это позволяет сделать плавные и предсказуемые повороты. Q49. Как я должен вычислять сопряженный кватернион?
Это можно сделать, изменяя знаки чисел векторной части кватерниона, т. е.: Qr = ( Qr.scalar, -Qr.vector ) ---------------------------------------------------------------- quaternion_conjugate( QUAT *qr, QUAT *qa ) { qr -> qw = qa -> qw; qr -> qx = -qa -> qx; qr -> qy = -qa -> qy; qr -> qz = -qa -> qz; } -------------------------------------- Q50. Как я должен вычислять обратный кватернион?
Точно так же, как и сопряженный кватернион. (см. Q49) Q51. Как я должен вычислять величину кватерниона?
Величина кватерниона может быть вычислена перемножением кватерниона с сопряженным с ним кватернионом т.е.: __________ / -- |Qr| = \/ Qr.Qr Это может быть выполнено как в следующем коде: ------------------------------------------------------------------- QFLOAT quaternion_magnitude( QUAT *qa ) { return( sqrt(qa->qw*qa->qw+ qa->qx*qa->qx+ qa->qy*qa->qy+qa->qz*qa->qz) ) } ------------------------------------------------------------------- Q52. Как я должен нормализовать кватернион?
Кватернионы могут быть нормализованы таким же способом, как и векторы. Сначала вычисляется величина кватерниона. Затем векторная и скалярная части кватерниона делятся на это значение. Единичный кватернион всегда имеет величину равную 1.0. Q53. Как я могу перемножить два кватерниона друг с другом?
Даны два кватерниона Q1 и Q2, цель перемножения - вычисление комбинации вращений Qr т.е.: Qr = Q1.Q2Для этого нужно вычислить такое выражение: Qr = Q1.Q2 = ( w1.w2 - v1.v2, w1.v2 + w2.v1 + v1 x v2 ) где v1 = (x,y,z) из Q1 w1 = (w) из Q1 v2 = (x,y,z) из Q2 w2 = (w) из Q2 в котором . и х скалярное (dot product) и векторное (cross product) произведение векторов. Это выполняет следующий сегмент кода: --------------------------------------------------- quaternion_multiply( QUAT *qr, QUAT *qa, QUAT *qb ) { qr.scalar = v3_dot( &qa->vector, &qb->vector ); v3_cross( &va, &qa->vector, &qb->vector ); v3_scalef( &vb, &qa->vector, &qb->scalar ); v3_scalef( &vc, &qb->vector, &qa->scaler ); v3_add( &va, &va, &vb ); v3_add( &qr->vector, &va, &vc ); quaternion_normalise( qr ); } --------------------------------------------------- Q54. Как должен я конвертировать кватернион в матрицу вращения?
Допустим, что кватернион был создан в следующей форме: Q = [X Y Z W] Тогда кватернион может быть преобразован в 3х3 матрицу вращения с помощью следующих выражений: | 2 2 | | 1 - 2Y - 2Z 2XY - 2ZW 2XZ + 2YW | | | | 2 2 | M = | 2XY + 2ZW 1 - 2X - 2Z 2YZ - 2XW | | | | 2 2 | | 2XZ - 2YW 2YZ + 2XW 1 - 2X - 2Y | | | Если нужна матрица 4х4, то нужно заполнить нижний и крайний правый ряды. Такую матрицу может сгенерировать следующий фрагмент кода: ---------------- xx = X * X; xy = X * Y; xz = X * Z; xw = X * W; yy = Y * Y; yz = Y * Z; yw = Y * W; zz = Z * Z; zw = Z * W; mat[0] = 1 - 2 * ( yy + zz ); mat[1] = 2 * ( xy - zw ); mat[2] = 2 * ( xz + yw ); mat[4] = 2 * ( xy + zw ); mat[5] = 1 - 2 * ( xx + zz ); mat[6] = 2 * ( yz - xw ); mat[8] = 2 * ( xz - yw ); mat[9] = 2 * ( yz + xw ); mat[10] = 1 - 2 * ( xx + yy ); //Далее заполняем четвёртый ряд и четвёртый столбец матрицы 4х4: mat[3] = mat[7] = mat[11 = mat[12] = mat[13] = mat[14] = 0; mat[15] = 1; ---------------- Q55. Как должен я конвертировать матрицу вращения в кватернион?
Следующий алгоритм производит конвертирование вращения в кватернион: Процесс вычисления разбит на следующие ступени: Вычисляется сумма Т элементов главной диагонали матрицы: 2 2 2 T = 4 - 4x - 4y - 4z 2 2 2 = 4( 1 -x - y - z ) = mat[0] + mat[5] + mat[10] + 1 Если Т больше, чем ноль тогда мгновенно получаем: S = 0.5 / sqrt(T) W = 0.25 / S X = ( mat[9] - mat[6] ) * S Y = ( mat[2] - mat[8] ) * S Z = ( mat[4] - mat[1] ) * S Если Т меньше или равно нулю тогда находим, наибольший элемент главной диагонали матрицы: В зависимости от того, в каком столбце матрицы расположен наибольший элемент, вычисления могут быть следующие: Столбец 0: S = sqrt( 1.0 + mr[0] - mr[5] - mr[10] ) * 2; Qx = 0.5 / S; Qy = (mr[1] + mr[4] ) / S; Qz = (mr[2] + mr[8] ) / S; Qw = (mr[6] + mr[9] ) / S; Столбец 1: S = sqrt( 1.0 + mr[5] - mr[0] - mr[10] ) * 2; Qx = (mr[1] + mr[4] ) / S; Qy = 0.5 / S; Qz = (mr[6] + mr[9] ) / S; Qw = (mr[2] + mr[8] ) / S; Столбец 2: S = sqrt( 1.0 + mr[10] - mr[0] - mr[5] ) * 2; Qx = (mr[2] + mr[8] ) / S; Qy = (mr[6] + mr[9] ) / S; Qz = 0.5 / S; Qw = (mr[1] + mr[4] ) / S; Кватернион тогда определяется как: Q = [ Qx Qy Qz Qw ] Q56. Как должен я конвертировать ось вращения и угол в кватернион?
Даны ось вращения и угол, следующий алгоритм генерирует кватернион: ------------------------------------------------ sin_a = sin( angle / 2 ) cos_a = cos( angle / 2 ) q -> x = axis -> x * sin_a q -> y = axis -> y * sin_a q -> z = axis -> z * sin_a q -> w = cos_a quaternion_normalise( q ); ------------------------------------------------ Необходимо нормализовать кватернион в случае, если какие-нибудь значения очень близки к нулю. Q57. Как должен я конвертировать кватернион в ось вращения и угол?
Следующий алгоритм конвертирует кватернион в ось вращения и угол: --------------------------------------------------- quaternion_normalise( qr ); cos_angle = qr -> qw; angle = acos( cos_angle ) * 2 * RADIANS; sin_angle = sqrt( 1.0 - cos_angle * cos_angle ); if ( fabs( sin_angle ) < 0.0005 ) sa = 1; axis -> vx = qr -> qx / sa; axis -> vy = qr -> qy / sa; axis -> vz = qr -> qz / sa; --------------------------------------------------- Q58. Как должен я конвертировать сферические углы вращения в кватернион?
Сама ось вращения сама может быть определена сферическими координатами (Широтой и Долготой) и углом вращения. В этом случае кватернион может быть вычислен так: ----------------------- sin_a = sin( angle / 2 ) cos_a = cos( angle / 2 ) sin_lat = sin( latitude ) cos_lat = cos( latitude ) sin_long = sin( longitude ) cos_long = cos( longitude ) qx = sin_a * cos_lat * sin_long qy = sin_a * sin_lat qz = sin_a * sin_lat * cos_long qw = cos_a ----------------------- Q59. Как должен я конвертировать кватернион в сферические углы вращения?
Следующий процесс преобразовывает кватернион в сферические координаты : ----------------------- cos_angle = q -> qw; sin_angle = sqrt( 1.0 - cos_angle * cos_angle ); angle = acos( cos_angle ) * 2 * RADIANS; if ( fabs( sin_angle ) < 0.0005 ) sa = 1; tx = q -> qx / sa; ty = q -> qy / sa; tz = q -> qz / sa; latitude = -asin( ty ); if ( tx * tx + tz * tz < 0.0005 ) longitude = 0; else longitude = atan2( tx, tz ) * RADIANS; if ( longitude < 0 ) longitude += 360.0; ----------------------- Q60. Как должен я конвертировать Эйлеровы углы вращения в кватернион?
Преобразование Эйлеровых углов вращения в кватернион может быть достигнуто путём перемножения кватернионов. Каждый угол вращения преобразовывается в пару ось-угол, с осью соответствующей одной из осей Евклидовой системы координат. Пары ось-угол преобразуется в кватернион и перемножаются. Результат последнего умножения есть искомый кватернион. Это демонстрирует следующий отрывок кода: --------------------------------------------- quaternion_from_euler( QUATERNION *q, VFLOAT ax, VFLOAT ay, VFLOAT az ) { VECTOR3 vx = { 1, 0, 0 }, vy = { 0, 1, 0 }, vz = { 0, 0, 1 }; QUATERNION qx, qy, qz, qt; quaternion_from_axisangle( qx, &vx, rx ); quaternion_from_axisangle( qy, &vy, ry ); quaternion_from_axisangle( qz, &vz, rz ); quaternion_multiply( &qt, &qx, &qy ); quaternion_multiply( &q, &qt, &qz ); } --------------------------------------------- Q61. Как должен я употреблять кватернионы для выполнения линейной интерполяции матриц?
Для многих программ с анимацией необходимо интерполировать положение данного объекта между двумя заданными позициями. Эти позиции могут быть определены контрольными точками. Для любого метода интерполяции должны быть известны по крайней мере две матрицы вращения и желаемый результат интерполируется между этими матрицами. Эти две матрицы называют стартовой и финишной (MS and MF). При использовании линейной интерполяции, промежуточная матрица вращения генерируется стыковочными уравнениями, параметр Т которых изменяется от 0.0 до 1.0. При Т=0 промежуточная матрица равна стартовой матрице. При Т=1 промежуточная матрица равна финишной матрице. Тогда промежуточная матрица вращения определяется как: MI = F( MS, MI, T ) где F - стыковочная функция. Первый шаг интерполяции - определение матрицы вращения, которая преобразовывает MS в MF. Это достигается использованием следующего выражения: -1 T = Ms . Mf
где Ms - стартовая матрица, Следующий шаг - преобразование этой матрицы в ось вращения и угол. Это достигается преобразованием матрицы в кватернион и в конечном итоге в требуемую ось вращения и угол. Для того, чтобы сгенерировать промежуточную матрицу вращения необходимо только измерять угол поворота и конвертировать этот угол и ось вращения назад, в матрицу вращения. При использовании библиотечной матрицы 4х4 делайте так: m4_transpose( mt, ms ); /* Inverse */ m4_mult( ms, mt, mb ); /* Rotation matrix */ m4_to_axisangle( ms, axis, angle ); /* Rotation axis/angle */ for ( t = 0; t < 1.0; t += 0.05 ) { m4_from_axisangle( mi, axis, angle * t ); /* Final interpolation */ ... whatever ... } где t - фактор интерполяции заданный между 0.0 и 1.0 Q62. Как должен я употреблять кватернионы для совершения кубической интерполяции матриц?
В некоторых программах может быть неудобным или вообще невозможным использование линейной интерполяции для анимации. В этих случаях альтернативой является употребление кубической интерполяции. При использовании кубической интерполяции должны быть известны, по крайней мере, четыре матрицы вращения. Каждая из них затем конвертируется в набор сферических вращений с помощью кватернионов и сферических углов вращения (т.е. широты, долготы и угла поворота). Затем они перемножаются с базовой матрицей Основной сплайновой кривой. Эти интерполированные матрицы потом могут употребляться для определения промежуточных сферических углов вращения. Как только промежуточные координаты становятся известными (т.е. долгота, широта и угол поворота), промежуточная матрица вращения тогда может быть сгенерирована с помощью кватернионных преобразований. При использовании библиотечной матрицы 4х4 делайте так: ---------------------------------------------------------------------- for ( n = 0; n < 4; n++ ) m4_to_spherical( mat[n], &v_sph[n] ); /* Spherical coordinates */ m4_multspline( m_cardinal, v_sph, v_interp ); /* Interpolation vector */ ... v3_cubic( v_pos, v_interp, t ); /* Interpolation */ m4_from_spherical( m_rot, v_pos ); /* Back to a matrix */ ---------------------------------------------------------------------- Другие статьи для программистов... |
||