Треугольник в трехмерном пространстве

Алгоритм Моллера — Трумбора — алгоритм для определения пересечения прямой (луча) и треугольника в трёхмерном пространстве, для работы которого не требуется предварительное вычисление уравнения плоскости, содержащей треугольник. [1] Данный алгоритм также может быть использован в компьютерной графике для реализации трассировки лучей с использованием полигональных сеток, состоящих из треугольников. [2]

Назван по имени авторов — Томаса Моллера (Tomas Möller) и Бена Трумбора (Ben Trumbore).

Реализация на языке C++ [ править | править код ]

Ниже представлена реализация алгоритма на языке C++ с использованием библиотеки GLM:

Голландский художник Мауриц Корнелис Эшер (M. C. Escher) всегда был особенно популярен среди программистов, инженеров и других технарей. Его остроумные рисунки невозможных конструкций заставляют мысленно наводить порядок в визуальной информации, в то же время его использование переплетающихся структур, явно вдохновленное математикой, предполагает знакомство с методами рекурсии в программном обеспечении.

Мне особенно нравится сочетание Эшером двух- и трехмерных изображений, например в работе «Рисующие руки» («Drawing Hands») 1948 года, в которой пара трехмерных рук постепенно возникает из двухмерного рисунка, который сам набрасывается трехмерными руками (рис. 1). Но это непосредственное наложение двух- и трехмерных изображений подчеркивает, что трехмерные руки приобретают глубину только благодаря проработке деталей и полутонов. Очевидно, что на рисунке все визуализируется на плоской бумаге.


Рис. 1. Литография «Рисующие руки» Эшера

В этой статье я хочу сделать нечто подобное: двухмерные графические объекты будут приобретать глубину и объемность по мере того, как они вырастают с поверхности экрана и начинают парить в трехмерном пространстве, а затем уходят обратно в плоский экран.

Но эти графические объекты не будут изображениями рук человека. Вместо этого я возьму простейшие трехмерные объекты: платоновы тела. Платоновы тела (Platonic solids) — это единственно возможный выпуклый многогранник, грани которого состоят из одинаковых правильных многоугольников с одинаковым количеством граней, сходящихся в каждой вершине. В трехмерном пространстве это тетраэдр (четыре треугольника), октаэдр (восемь треугольников), икосаэдр (20 треугольников), куб (шесть квадратов) и додекаэдр (12 пятиугольников).

Платоновы тела популярны в программировании простейшей трехмерной графики, потому что они, в целом, просты в определении и сборке. Формулы для вершин можно найти, например, в Википедии.

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

Моя стратегия заключается в том, чтобы определить эти объекты, используя треугольники в трехмерном пространстве, а затем применять трехмерные преобразования для их поворота. Координаты преобразованных треугольников после этого уплощаются на двухмерное пространство игнорированием Z-координаты, где они используются для создания объектов ID2D1Mesh; потом выполняется рендеринг этих объектов методом FillMesh объекта ID2D1DeviceContext.

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

Трехмерные точки и преобразования

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

Любопытно, что в Direct2D есть структура D2D1_MATRIX_4X4_F и класс Matrix4x4F в пространстве имен D2D1, подходящие для представления матриц трехмерных преобразований. Однако эти типы данных предназначены только для использования с методами DrawBitmap, определенными в ID2D1DeviceContext, как уже демонстрировалось в прошлом выпуске этой рубрики. В частности, в Matrix4x4F даже нет метода Transform, который мог бы применить преобразование к трехмерной точке. Вам пришлось бы самостоятельно реализовать перемножение матриц.

Более подходящее место для поиска типов трехмерных данных — библиотека DirectX Math, которая используется и Direct3D-программами. В этой библиотеке определены более 500 функций — все их имена начинаются с букв «XM» — и несколько типов данных. Все это объявлено в заголовочном файле DirectXMath.h и сопоставлено с пространством имен DirectX.

Все функции до единой в библиотеке DirectX Math используют тип данных XMVECTOR, который является набором из четырех чисел. XMVECTOR годится для представления двух- и трехмерных точек (с W-координатой или без) или цвета (с альфа-каналом или без). Вот как вы определили бы объект типа XMVECTOR:

Заметьте: я сказал, что XMVECTOR — это набор из «четырех чисел», а не из «четырех значений с плавающей точкой» или «четырех целочисленных значений». Я не могу сказать точнее, потому что реальный формат этих четырех чисел в объекте XMVECTOR является аппаратно-зависимым.

XMVECTOR не является обычный типом данных! На самом деле это прокси для четырех аппаратных регистров в чипе процессора, а именно SIMD-регистров (single instruction multiple data), используемых с SSE (streaming SIMD extensions), которые реализуют параллельную обработку. В процессорах x86 эти регистры содержат значения с плавающей точкой единичной точности, но в процессорах ARM (устанавливаемых в устройства под управлением Windows RT) это целые значения, определенные так, что они имеют дробные части.

Читайте также:  Текст запроса который будет фактически исполняться системой

По этой причине вы не должны пытаться напрямую обращаться к полям объекта XMVECTOR (если только вы не знаете точно, что именно делаете). Вместо этого в библиотеку DirectX Math включено много функций для записи в поля любых значений — от целых до чисел с плавающей точкой. Вот распространенный пример:

Есть также функции для получения значений индивидуальных полей:

Поскольку этот тип данных является прокси аппаратных регистров, использовать его можно лишь с ограничениями. Подробнее об определении членов структуры типа XMVECTOR и передачи аргументов XMVECTOR в функции см. онлайновое руководство «DirectXMath Programming Guide» (bit.ly/1d4L7Gk).

Однако, в целом, вы будете использовать XMVECTOR по большей части в коде, локальном для некоего метода. В качестве более универсального хранилища трехмерных точек и векторов в библиотеке DirectX Math определены другие типы данных, которые являются простыми, обыкновенными структурами, например XMFLOAT3 (содержит три поля типа float с именами x, y и z) и XMFLOAT4 (дополнена четвертым полем с именем w). В частности, для хранения массивов точек вы предпочтете задействовать XMFLOAT3 или XMFLOAT4.

Очень легко переносить значения между XMVECTOR и XMFLOAT3 или XMFLOAT4. Допустим, вы используете XMFLOAT3 для хранения трехмерной точки:

Когда вам нужно вызвать одну из функций DirectX Math, требующих XMVECTOR, вы можете загрузить значение в XMVECTOR через функцию XMLoadFloat3:

Значение w в XMVECTOR инициализируется 0. После этого можно использовать объект XMVECTOR в различных функциях DirectX Math. Чтобы сохранить значение из XMVECTOR обратно в объект XMFLOAT3, вызовите:

Аналогично XMLoadFloat4 и XMStoreFloat4 переносят значения между объектами XMVECTOR и XMFLOAT4, и этот вариант зачастую предпочтительнее, если важна W-координата.

В общем случае вы будете работать с несколькими объектами XMVECTOR в одном блоке кода, часть из которых соответствует нижележащим объектам XMFLOAT3 или XMFLOAT4, а часть является просто промежуточной. Вскоре вы увидите примеры.

Ранее я сказал, что каждая функция в библиотеке DirectX Math включает XMVECTOR. Если вы исследовали эту библиотеку, то, возможно, нашли некоторые функции, которые на самом деле не требуют XMVECTOR, но включают объект типа XMMATRIX.

Тип данных XMMATRIX — это матрица 4×4, подходящая для трехмерных преобразований, но в действительности это четыре объекта XMVECTOR, по одному в каждой строке:

Так что я все правильно говорил, поскольку все функции DirectX Math, требующие объекты XMMATRIX, на самом деле работают с объектами XMVECTOR, а XMMATRIX имеет те же ограничения, что и XMVECTOR.

Как и в случае обычной структуры XMFLOAT4, позволяющей перемещать значения между ней и объектом XMVECTOR, вы можете использовать другую обычную структуру, XMFLOAT4X4, чтобы сохранять матрицу 4×4 и перемещать данную матрицу между этой структурой и XMMATRIX, вызывая функции XMLoadFloat4x4 и XMStoreFloat4x4.

Если вы загрузили трехмерную точку в объект XMVECTOR (с именем vector, например), а матрицу преобразования — в объект XMMATRIX с именем matrix, то можете применить это преобразование к точке следующим образом:

Единственное отличие в том, что XMVector4Transform использует значение w из XMVECTOR, а XMVector3Transform предполагает, что оно равно 1, что правильно при реализации трехмерной трансляции.

Однако, если у вас есть массив значений XMFLOAT3 или XMFLOAT4 и вы хотите применить преобразование ко всему массиву, есть гораздо более эффективное решение: функции XMVector3TransformStream и XMVector4TransformStream применяют XMMATRIX к массиву значений и сохраняют результаты в массиве значений XMFLOAT4 (независимо от входного типа).

Бонус: поскольку XMMATRIX на самом деле является SIMD-регистрами в процессоре, который реализует аппаратную поддержку SSE, процессор может использовать параллельную обработку при применении этого преобразования к массиву точек и тем самым ускорить один из самых медленных этапов в рендеринге трехмерной графики.

Определение платоновых тел

Сопутствующий этой статье код содержит единственный проект для Windows 8.1 с именем PlatonicSolids. Программа использует Direct2D для рендеринга трехмерных изображений на пяти платоновых телах.

Как и все трехмерные фигуры, эти тела можно описать набором треугольников в трехмерном пространстве. Я знал, что мне понадобится использовать XMVector3TransformStream или XMVector4TransformStream для преобразования массива трехмерных треугольников и что выходной массив этих двух функций всегда будет массивом объектов XMFLOAT4, поэтому я решил задействовать XMFLOAT4 и для входного массива. В итоге я определил свою структуру для трехмерного треугольника так:

На рис. 2 показаны некоторые дополнительные закрытые структуры данных, определенные в PlatonicSolidsRenderer.h, которые хранят информацию для описания и рендеринга трехмерной фигуры. Каждое из пяти платоновых тел — это объект типа FigureInfo. Наборы srcTriangles и dstTriangles хранят оригинальные треугольники («источник») и конечные («destination») треугольники после применения преобразований масштабирования и вращения. Оба набора имеют размер, равный произведению faceCount на trianglesPerFace. Заметьте, что srcTriangles.data и dstTriangles.data фактически являются указателями на структуры XMFLOAT4 и поэтому могут быть аргументами функции XMVector4TransformStream. Как вы увидите, это происходит в методе Update класса PlatonicSolidRenderer.

Рис. 2. Структуры данных, применяемые для хранения трехмерных фигур

Поле renderInfo — это набор объектов RenderInfo, по одному на каждую грань фигуры. Два члена этой структуры также определяются в методе Update и просто передаются методу FillMesh объекта ID2D1DeviceContext при выполнении метода Render.

Читайте также:  Тип принтера только с черно белой печатью

Конструктор класса PlatonicSolidsRenderer инициализирует каждый из пяти объектов FigureInfo. На рис. 3 показан этот процесс для простейшей из пяти трехмерных фигур — тетраэдра.

Рис. 3. Определение тетраэдра

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

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

Для простоты преобразования трехмерных координат в двухмерные я основывал эти фигуры на системе координат, в которой положительные X-координаты увеличиваются вправо, а положительные Y-координаты — вниз. (В программировании трехмерной графики чаще используют увеличение положительных Y-координат вверх.) Я также исходил из предположения, что положительные Z-координаты исходят из экрана. Следовательно, это левосторонняя система координат (left-hand coordinate system). Если вы расположите указательный палец левой руки в направлении положительной оси X, а средний палец — в направлении положительной оси Y, ваш большой палец укажет положительную ось Z.

Предполагается, что камера расположена в какой-то точке на положительной оси Z и смотрит в направлении начала координат.

Вращения в трехмерном пространстве

Метод Update в PlatonicSolidsRenderer выполняет анимацию, которая состоит из нескольких частей. Когда программа начинает работать, отображаются пять платоновых тел, но они появляются плоскими, как показано на рис. 4.


Рис. 4. Программа PlatonicSolids в начале выполнения

Очевидно, что они не воспринимаются как трехмерные объекты!

Через 2,5 секунды объекты начинают вращаться. Метод Update вычисляет углы поворота и масштабный множитель, учитывая размер экрана, а затем использует функции DirectX Math. Такие функции, как XMMatrixRotationX, вычисляют объект XMMATRIX, представляющий поворачивание вокруг оси X. XMMATRIX также определяет операторы перемножения матриц, чтобы результаты этих функций можно было перемножить друг на друга.

На рис. 5 видно, как вычисляется итоговое матричное преобразование и применяется к массиву объектов Triangle3D в каждой фигуре.

Рис. 5. Вращение фигур

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

Перекрытие и скрытые поверхности

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

Однако в случае выпуклого полиэдра эта задача сравнительно проста. Возьмем куб. По мере вращения куба в пространстве вы в основном видите три грани, а иногда всего одну или две. И никогда — четыре, пять или все шесть граней.

Как определить для конкретной грани вращающегося куба, какие грани видны, а какие нужно скрыть? Подумайте о векторах (часто визуализируемых как стрелки с конкретным направлением), перпендикулярных каждой грани куба и указывающих вовне куба. Их называют векторами нормали поверхности (surface normal vectors).

Только если вектор нормали поверхности имеет положительную часть по оси Z, эта поверхность будет видна наблюдателю, смотрящему на объект с положительной оси Z.

С математической точки зрения, вычисление нормали поверхности для треугольника достаточно прямолинейно: три вершины треугольника определяют два вектора, а два вектора (V1 и V2) в трехмерном пространстве определяют плоскость, и перпендикуляр к этой плоскости вычисляется как векторное произведение (vector cross product) (рис. 6).


Рис. 6. Векторное произведение

“right hand” «правосторонняя»
“left hand” «левосторонняя»

Реальное направление этого вектора зависит от того, какой является система координат — левосторонней или правосторонней. Например, в правосторонней системе координат вы можете определить направление векторного произведения V1×V2, описав кривую пальцами своей правой руки с V1 на V2. Указательный палец укажет в направлении векторного произведения. В случае левосторонней системы координат делайте то же самое левой рукой.

Применительно к любому конкретному треугольнику, образующему эти фигуры, первый шаг — загрузка трех вершин в объекты XMVECTOR:

Затем два вектора, представляющие две стороны треугольника, можно вычислить вычитанием point2 и point3 из point1, используя удобные функции DirectX Math:

Все платоновы тела в этой программе определяются с помощью треугольников, три точки которых размещаются по часовой стрелке от point1 к point2 и далее к point3, когда на треугольник смотрят извне этой фигуры. Нормаль поверхности, указывающую вовне фигуры, можно вычислить, используя функцию DirectX Math, которая получает векторное произведение:

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

Все дело в затенении

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

Читайте также:  Штатная частота работы видеочипа

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

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

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

Готовясь к следующей задаче, я хочу нормализовать как вектор нормалей поверхностей, так и вектор освещения:

Функция XMVector3Normalize вычисляет абсолютную величину вектора (magnitude of the vector), используя трехмерную форму теоремы Пифагора, а затем делит три координаты на эту величину. Конечный вектор имеет абсолютную величину, равную 1.

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

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

Скалярное произведение дает нам одно число, а не вектор, поэтому все поля объекта XMVECTOR, возвращаемые из этой функции, хранят одни и те же значения.

Чтобы создать иллюзию того, будто вращающиеся платоновы тела волшебным образом обретают объемность по мере появления из плоского экрана, программа PlatonicSolids анимирует значение lightIntensity от 0 до 1 и обратно к 0. Нулевое значение означает отсутствие направленного освещения и эффекта трехмерности, тогда как значение 1 обеспечивает максимальную объемность. Это значение lightIntensity используется в сочетании со скалярным произведением для вычисления общего коэффициента освещения:

Первое значение 0.5 в этой формуле относится к окружающему свету, а второе значение 0.5 позволяет варьировать totalLight в диапазоне от 0 до 1 в зависимости от значения скалярного произведения. (Теоретически это не совсем правильно. Отрицательные значения скалярного произведения следует обнулять, потому что они дают общее освещение, меньшее окружающего.)

Затем с помощью totalLight вычисляются цвет и кисть для каждой грани:

Результат с максимальной объемностью показан на рис. 7.


Рис. 7. Программа PlatonicSolids, отображающая максимальную объемность фигуры

Чарльз Петцольд (Charles Petzold) — давний «пишущий» редактор MSDN Magazine и автор книги «Programming Windows, 6th edition» (O’Reilly Media, 2013) о написании приложений для Windows 8. Его веб-сайт находится по адресу charlespetzold.com.

Выражаю благодарность за рецензирование статьи эксперту Microsoft Дугу Эриксону (Doug Erickson).


Вобщем подкинули мне задачку.

Подписка (RSS)
Площадь двух треугольников

Какая у вас оценка в школе по геометрии?

На картинке вы видите 2 треугольника. Треугольники состоят из четырех фигур. Площадь фигур, из которых состоят треугольники, одинакова. Что у верхнего, что у нижнего (можете вырезать из бумаги и проверить). Что будет если фигуры немного перемешать?

Площадь треугольника
Ключевые слова: треугольник, площадь, высота, формула Герона
Ниже представлены 5 формул для нахождения площади треугольника.
Обозначения:

* ha – высота, проведенная к стороне a.
* p – полупериметр, т.е. половина от суммы всех сторон треугольника.
* R – радиус описанной окружности.
* r – радиус вписанной окружности.

Вычисление площади треугольника в пространстве с помощью векторов

Пусть вершины треугольника находятся в точках
Введём вектор площади Длина этого вектора равна площади треугольника, а направлен он по нормали к плоскости треугольника:
Положим проекции треугольника на координатные плоскости. При этом
и аналогично
Площадь треугольника равна
Альтернативой служит вычисление длин сторон (по теореме Пифагора) и далее по формуле Герона.
Фо́рмула Геро́на позволяет вычислить площадь треугольника (S) по его сторонам a, b, c:
где р — полупериметр треугольника:

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

Если два угла одного треугольника соответственно равны двум углам другого, то треугольники подобны.
Второй признак

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

Если три стороны одного треугольника пропорциональны трем сходственным сторонам другого, то треугольники подобны.

Синус и тангенс угла
Синусом острого угла прямоугольного треугольника называется отношение противолежащего катета к гипотенузе.
Тангенсом угла прямоугольного треугольника называется отношение противолежащего катета к прилежащему катету. Тангенс угла α обозначается: tg α.

Оцените статью
Добавить комментарий

Adblock
detector