OpenGL SuperBible (6th Edition) / OpenGL Супер Книга (6-ое издание): Математика для 3D-графики
| Английский оригинал | Перевод на русский | |
|---|---|---|
Сожалеем, но текст оригинала доступен только зарегистрированным пользователям. |
Глава 4. Математика для 3D-графики vk955 15.08.14 в 10:39 |
|
|
Насколько страшна эта глава? vk955 15.08.14 в 11:11 |
||
|
На самом деле, вы можете прекрасно справиться, не понимая тонкостей математики 3D-графики, точно так же, как вы можете вести свой автомобиль каждый день, не зная вообще ничего об автомобильной механике и двигателе внутреннего сгорания. Но вам лучше знать о вашем автомобиле достаточно, чтобы понимать: время от времени нужно менять масло, регулярно заполнять бензобак и необходимо менять покрышки, когда они стираются. Эти знания делают вас ответственным (и осторожным!) владельцем автомобиля. Если вы хотите быть ответственным и умелым OpenGL программистом, то это относятся и к вам. По крайней мере вам нужно понимать основы, чтобы знать что вы можетe сделать, и какие лучше использовать инструменты для выполнения работы. По мере практики вы ощутите, что математические матрицы и векторы постепенно обретают смысл, и будете развивать более интуитивные (и мощные) навыки, чтобы в полной мере использовать понятия, которые мы представим в этой главе. vk955 15.08.14 в 14:32 |
||
|
Но даже если вы еще не умеете перемножать матрицы в уме, вам нужно знать, что это такое и какую роль они играют в OpenGL. Но прежде, чем вы побежите стряхивать пыль с учебника алгебры (у всех он есть?), мы напомним: в библиотеке sb6 есть компонент, называемый vmath, который содержит несколько полезных классов и функций для представления и манипулирования векторами и матрицами. Они могут быть использованы непосредственно с OpenGL и очень похожи по синтаксису и внешнему виду на GLSL - язык, на котором вы будете писать свои шейдеры. Но хоть вы и не должны совершать матричные и векторные преобразования самостоятельно, будет отлично, если вы будете знать, что это такое и как применять. Видите - вы можете усидеть сразу на двух стульях! vk955 15.08.14 в 17:27 |
||
|
Интенсивный курс математики в 3D-графике vk955 16.08.14 в 03:51 |
||
|
Вектор, или куда ведет этот путь? vk955 16.08.14 в 04:49 |
+1 | |
|
Рисунок 4.1 показывает точку в пространстве (взятую произвольно) и стрелку, нарисованную от начала системы координат к этой точке. Точку можно рассматривать как вершину, когда вы составляете треугольник, а стрелку как вектор. В первую очередь, вектор - это просто направление от начала координат к точке в пространстве. Мы используем векторы в OpenGL всё время для представления направленных величин. Например, ось x - вектор (1, 0, 0). Это означает, отложить одну единицу в положительном направлении по оси x, и ноль в направлении по осям y и z. Вектор, также означает направление, куда мы движемся, например, в какую сторону указывает камера или в каком направлении бежать, чтобы уйти от крокодила! Вектор настолько фундаментальное понятие в OpenGL, что в GLSL для него предусмотрены типы разных размеров, которым даны имена, такие как vec3 и vec4 (представляющие соответственно 3- и 4-мерные векторы). vk955 16.08.14 в 05:54 |
||
|
Рисунок 4.1: Точка в пространстве - это и вершина и вектор. vk955 16.08.14 в 09:55 |
||
|
Вторая величина, которую представляет вектор, это модуль. Модуль вектора - это его длина. Для нашего вектора (1, 0, 0) длина вектора равна единице. Вектор с длиной равной одному называется единичным вектором. Если вектор не единичный, а мы хотим изменить его длину до единицы, то мы называем это нормализацией. Процесс нормализации вектора заключается в масштабировании его таким образом, что длина становится равной единице. Такой вектор называется нормализованным. Единичные векторы важны, когда мы хотим указать лишь направление, а не длину. Также, если длины векторов появятся в уравнениях, которые мы будем использовать, они станут намного проще при длинах равных 1! Модуль также может быть важной величиной; например, он может сказать, как далеко мы должны двигаться в данном направлении - как далеко мне нужно убежать от этого крокодила. vk955 16.08.14 в 10:35 |
||
|
Векторы (и матрицы) настолько важные понятия в 3D-графике, что они объекты первого класса в GLSL — язык, в котором вы будете писать ваши шейдеры. Тем не менее, это не так в C++ подобных языках. Чтобы вы могли использовать их в ваших программах на C++, библиотека vmath, которая идёт с исходным кодом этой книгой, содержит классы, которые могут представить векторы и матрицы, которые называются соответственно с аналогами из GLSL: к примеру, vmath::vec3 может представить трёхкомпонентным вектором из чисел с плавающей запятой (x, y, z) и vmath::vec4 может представить вектор из четырёх компонентов чисел с плавающей запятой (x, y, z, w) и так далее. Координата w добавлена, чтобы сделать вектор однородным, но как правило, всегда имеет значение 1.0. Значения x, y, и z в дальнейшем могут быть разделены на w, когда он равен 1.0, по сути оставляет значения xyz прежними. Классы в vmath фактически являются шаблонными классами с определением типов для предоставления общих типов, таких как значения с плавающей запятой одинарной и двойной точностей, и знаковые и без знаковые целочисленные переменные. vmath::vec3 и vmath::vec4 определены просто как следующим образом: vk955 16.08.14 в 12:10 |
||
|
Объявлять трёхкомпонентный вектор вот так просто: vk955 16.08.14 в 13:20 |
||
|
vec3 vVertex1(0.0f, 0.0f, 1.0f); vk955 16.08.14 в 13:36 |
||
|
Теперь, массив трёхкомпонентных вершин, как для треугольника может быть объявлен как: vk955 16.08.14 в 13:37 |
||
|
vec3 vVerts[] = { vec3(-0.5f, 0.0f, 0.0f), vk955 16.08.14 в 13:39 |
||
|
Это должно быть знакомым, этот код был представлен в разделе "Рисуем наш первый треугольник" в главе 2. Библиотека vmath также включает много-много математических функций и перегрузки большинства операций её класса, позволяя складывать, вычитать, умножать, транспонировать и так далее векторы и матрицы vk955 16.08.14 в 13:51 |
||
|
Нам нужно быть осторожными, чтобы не пропустить четвёртый компонент W. Большую часть времени, когда вы определяете положение вершин геометрической фигуры, трёхкомпонентные вершины это всё, что вам нужно хранить и отправлять в OpenGL. Для многих направленных векторов, таких как нормаль к поверхности (вектор указывающий перпендикулярно к поверхности, который используется для расчетов освещения) достаточно использовать трёхкомпонентный вектор. Однако, мы скоро погрузимся в мир матриц, и чтобы превратить 3D вершину, вы должны умножить её на матрицу преобразования размером 4 х 4. Правила такое: вы должны умножать четырёхкомпонентный вектор на матрицу 4 x 4, если вы попробуете умножить трёхкомпонентный вектор на матрицу 4 x 4... крокодилы съедят вас! Подробности на счёт этого будут скоро. По сути, если вы собираетесь делать свои собственные матричные операции над векторами, тогда возможно вы будете использовать четырёхкомпонентный вектор, во многих случаях. vk955 16.08.14 в 14:12 |
||
|
Общие операции над векторами vk955 16.08.14 в 15:43 |
||
|
vmath::vec3 a(1.0f, 2.0f, 3.0f); vk955 16.08.14 в 15:47 |
||
|
Впрочем, есть намного больше операций с векторами, которые будут объяснены с математической точки зрения в следующих подразделах. Они также имеют реализации в библиотеке vmath, которая будет описана здесь. vk955 16.08.14 в 17:12 |
||
|
Скалярное произведение vk955 16.08.14 в 17:40 |
||
|
Рисунок 4.2: Скалярное произведение — косинус угла между двумя векторами vk955 16.08.14 в 18:17 |
||
|
Математически, скалярное произведение двух векторов v1 и v2 считается так: vk955 16.08.14 в 19:02 |
||
|
Как упоминалось ранее, скалярное произведение между парой единичных векторов имеет значение между -1.0 и +1.0, что дает косинус угла между ними. Немного выше по уровню функция vmath::angle, вообще-то, возвращает угол в радианах. vk955 16.08.14 в 20:06 |
||
|
float angle(const vmath::vec3& u, const vmath::vec3& v); vk955 16.08.14 в 20:07 |
||
|
Векторное произведение vk955 16.08.14 в 20:10 |
||
|
где n это единичный вектор, который перпендикулярен и v1, и v2. Это значит, что если вы нормализуете результат векторного произведения, вы получите нормаль к плоскости. Если оба v1 и v2 имеют длину один, и известно, что они перпендикулярны друг к другу, то вам не нужно будет нормализовать результат, так как он и так будет единицей. Рисунок 4.3: показывает два вектора v1 и v2, v3 - результат их векторного произведения. vk955 16.08.14 в 20:25 |
||
|
Рисунок 4.3: Векторное произведение возвращает перпендикуляр к его параметрам. vk955 17.08.14 в 09:03 |
||
|
Векторное произведение двух трёхмерных v1 и v2 могут быть сосчитаны следующим образом: vk955 17.08.14 в 17:09 |
||
|
Опять же, библиотека vmath имеет функции, которые принимают векторное произведение двух векторов и возвращают результирующий вектор: одна функция - метод трёхкомпонентного класса, а другая глобальная функция. vk955 17.08.14 в 17:16 |
||
|
В отличие от скалярного произведения, здесь порядок векторов важен. На рисунке 4.3, v3 является результатом векторного произведения v2 и v1. Если бы вы поменяли местами v1 и v2, то результирующий вектор v3 смотрел бы в противоположную сторону. Применение векторного произведения разнообразно, от нахождения нормалей к поверхностям треугольников до построения матриц преобразования. vk955 17.08.14 в 17:19 |
||
|
Длина вектора vk955 17.08.14 в 17:32 |
||
|
Квадратный корень суммы квадратов компонентов вектора. Это простая теорема Пифагора, только в двух измерениях - квадрат гипотенузы равен сумме квадратов катетов. Это распространяется на любое количество измерений, библиотека vmath включает функции для таких вычислений. vk955 17.08.14 в 17:54 |
||
|
template <typename T, int len> vk955 17.08.14 в 17:54 |
||
|
Отражение и преломление vk955 17.08.14 в 17:56 |
||
|
Рисунок 4.4: Отражение и преломление vk955 17.08.14 в 19:37 |
||
|
Нам интересно вычисление в трёхмерном пространстве (всё-таки эта книга о 3D-графике), хотя на рисунке 4.4 показана система только в двух измерениях. Формула для вычисления Rreflect vk955 17.08.14 в 19:45 |
||
|
Rreflect = Rin – (2N · Rin)N vk955 17.08.14 в 19:48 |
||
|
и формула для вычисления Rrefract с заданным η vk955 17.08.14 в 19:50 |
||
|
Чтобы получить желаемый результат и R и N должны быть единичными векторами (то есть они должны быть нормализованы перед применением). Две vmath функции reflect() и refract() реализовывают эти уравнения. vk955 17.08.14 в 19:53 |
||
|
Матрицы vk955 17.08.14 в 20:05 |
||
|
С точки зрения математики, матрица не что иное, как набор чисел, расположенных в равномерных строках и столбцах - в программировании это двумерный массив. Матрица не обязательно может быть квадратной, но все строки должны иметь одинаковое количество элементов, и все столбцы тоже должны иметь одинаковое количество элементов. Ниже приведена подборка матриц. Они ничего не значат, лишь служат для демонстрации их строения. Обратите внимание, матрица может иметь только один столбик или одну строку. Числа записанные в одну строку или столбец называются просто векторами, как уже обсуждалось ранее. Дальше мы увидим, что некоторые матрицы - это таблица из столбцов векторов. vk955 18.08.14 в 07:33 |
||
|
В литературе программирования 3D-графики термины "матрица" и "вектор" важны. Когда вы будете иметь дело с этими величинами, вы также встретите термин "скаляр". Скаляр - это просто число, означающее величину либо количество !ПРОПУСТИЛ!. Матрицы можно перемножать и складывать не только между собой, но еще и с векторами и скалярами. Умножая точку (представленную вектором) на матрицу (преобразования) получаем новую преобразованную точку (другой вектор). Матричные преобразования на самом деле не так уж сложно понять, но могут показаться пугающими сначала. Вы должны познакомится с матричными преобразованиями, потому что эти понятия - основа многих задач в 3D. К счастью, с помощью лёгких для понимания вещей можно делать довольно-таки невероятные вещи с OpenGL. Со временем, и с небольшой практикой, обучаясь, вы освоите этот математический инструмент самостоятельно. vk955 18.08.14 в 16:09 |
||
|
А пока, как ранее с векторами, вы найдете несколько полезных матричных функций и возможностей в библиотеке vmath. Исходный код этой библиотеке доступен в файле vmath.h в папке исходного кода книги. Эта библиотека 3D-математики значительно упрощает многие задачи в этой и грядущих главах. Одна полезная возможность этой библиотеки - недостаток невероятно умного и хорошо оптимизированного кода! Это делает библиотеку переносимой и легкой для понимания. Вы также увидите, что в ней GLSL подобный синтаксис. vk955 18.08.14 в 19:17 |
||
|
В 3D-задач программирования с OpenGL, вы будете использовать матрицы трёх размеров: 2 x 2, 3 x 3, 4 x 4. Библиотека vmath имеет матричные типы данных, которые соответствуют тем, которые определены GLSL, такие как vk955 18.08.14 в 19:36 |
||
|
Как GLSL, матричные классы в vmath определены общие операторы, такие как сложение, вычитание, унарный минус, умножение и деление вместе с конструкторами и операторами сравнения. Опять же, матричные классы в vmath построены с использованием шаблонов и включается в себя определение типов для чисел с плавающей точкой одинарной и двойной точностей и для знакового и без знакового целого матричного типа. vk955 19.08.14 в 07:08 |
||
|
Матричные конструкция и операторы vk955 19.08.14 в 07:43 |
||
|
GLfloat matrix[16]; // Прекрасно дружит с матрицами в OpenGL vk955 19.08.14 в 09:00 |
||
|
OpenGL может использовать второй вариант, но первый эффективнее представить. Сейчас это станет яснее. Эти 16 элементов представлены в матрице 4 x 4, как показано ниже. Когда в массиве элементы проходят вниз по столбцам один за другим, мы называем это главным порядком по столбцу. В памяти, двумерный массив 4 x 4 (второй вариант в предыдущем коде) разложен по порядку, где строка главная. Такой математический термин, смены порядка, называется транспонирование. vk955 19.08.14 в 09:08 |
||
|
Представление матрицы сверху с главным порядком по столбцу в памяти выглядит следующим образом: vk955 19.08.14 в 09:52 |
||
|
static const float A[] = vk955 19.08.14 в 09:54 |
