Вычисление нормали/перпендикуляра
Нормаль (т.е. вектор, перпендикулярный плоскости) часто необходим в процессе создания меша и также может быть полезен при отслеживании пути и других ситуациях. Имея три точки на плоскости, скажем угловые точки треугольника меша, легко вычислить нормаль. Выберите любую из трех точек и затем вычтите ее из каждой из двух остальных точек, чтобы получить два вектора:-

var a: Vector3; var b: Vector3; var c: Vector3; var side1: Vector3 = b - a; var side2: Vector3 = c - a;
Векторное произведение этих векторов даст третий вектор, перпендикулярный к искомой поверхности. Для определения порядка, в котором два вектора должны быть использованы в функции векторного произведения, можно использовать “правило левой руки”. Если смотреть сверху на поверхность (из которой должна выходить нормаль), первый вектор должен следовать по часовой стрелке за вторым:-
var perp: Vector3 = Vector3.Cross(side1, side2);
Результат будет направлен в противоположную сторону, если поменять порядок исходных векторов.
Для мешей нормаль должна быть нормализована. Это может быть сделано с помощью свойства normalized, но есть другая хитрость, которая иногда может быть полезна. Вы можете нормализовать перпендикуляр, разделив его на его же длину:-
var perpLength = perp.magnitude; perp /= perpLength;
Оказывается, площадь треугольника равна perpLength / 2. Это полезно, если вам нужно найти площадь поверхности всего меша, или вы хотите выбрать треугольники случайно, с вероятностью на основе их относительной площади.
Вычисление нормалей
В данной работе присутствует два вида примитивов, используемых в построении сцены. Это полигон (треугольник) и эллипсоид.
Вычисление нормали к полигону
Векторное произведение — это вектор перпендикулярный к плоскости, которая образуется двумя векторами. В случае треугольника, нормализованное векторное произведение к двум его сторонам будет являться нормалью. Достаточно найти нормаль один раз, при инициализации сцены, вычислять нормаль каждый раз нет смысла, т.к. в любой точке треугольника нормали одинаковы, и это сократит вычислительные затраты.
Пусть задан треугольник ABC и мы знаем координаты всех его вершин.
Вычислим координаты двух векторов AB и AC:
Найдём векторное произведение векторов: N = ABxAC
Полученный вектор нормализуем. Координаты данного вектора, буду являться координатами нормали к полигону:
Вычисление нормали к сфере в заданной точке
Для вычисления нормали к точке на сфере, необходимо вычесть координаты
центра сферы, из координат точки поиска.
где N — вектор нормали, P — точка к которой надо найти нормаль, O — центр сферы.
Полученный вектор необходимо нормализовать. Поделим вектор N на радиус сферы.
В итоге мы получим нормаль к сфере в заданной точке.
Поиск пересечения с объектами
Важнейшей частью алгоритма обратной трассировки лучей является определение пересечения. Способ определения точки пересечения зависит от того, какой это объект, и каким образом он представлен. Для ускорения поиска пересечения рекомендуется использовать метод оболочек. Каждый объект полностью помещается в оболочку, нахождение пересечения с которой быстрее, чем с объектом. Например, в сферу. Если луч пересёк оболочку, то необязательно, что этот луч пересечёт и объект. Необходимо продолжить поиск пересечения луча с объектом.
Любая точка луча удовлетворяет уравнению:
где R- радиус-вектор произвольной точки, принадлежащей лучу, A — радиус-вектор начальной точки луча, V — вектор направления луча, t — параметр.
Поиск пересечения с полигоном
Поиск пересечения с треугольником состоит из двух этапов: поиск пересечения луча с плоскостью треугольника и определение нахождения точки внутри него.
Запишем уравнение плоскости:
Q(x, y, z) = Ax + By + Cz +D = 0. (2.12)
Коэффициенты A, B, C совпадают с координатами нормали к этой плоскости. Координаты нормали плоскости совпадают с координатами нормали треугольника. Нормаль треугольника была рассчитана при инициализации сцены.
Выразим свободный член D:
D = -Ax -By — Cz (2.13)
Теперь для нахождения свободного члена D достаточно подставить координаты любой точки треугольника. Например, любую из вершин.
По аналогии с нормалью треугольника, свободный член в ходе работы программы не изменяется, поэтому вычисли его при инициализации сцена. Пересчитывать его необходимо только при изменении положения треугольника.
Теперь для нахождения точки пересечения подставим уравнения луча (2.11) в
уравнение плоскости (2.12):
A (x1 + at) + B (y1 + bt) + C (z1 + ct) + D = 0 (2.14)
Если знаменатель дроби равен нулю, значит луч параллелен плоскости, в которой лежит треугольник, следовательно, точки пересечения нет.
Иначе, для нахождения координат точки пересечения надо подставить найденное значение параметра t в уравнение луча (2.11). Назовем точку пересечения D. Мы получим координаты xD, yD, zD.
Необходимо определить, попала ли точка D внутрь треугольника. Найдем координаты векторов AB, BC, CA и координаты векторов AD, BD, CD.
Определим три векторых произведения:
nb = BC x BD, (2.16)
Если все три вектора сонаправлены, то точка D лежит внутри треугольника.
Для проверки на сонаправленность, проверяет знаки соответствующих координат всех векторов.
Данный алгоритм может быть ускорен различными тестами. Одним из таких тесов является габаритный тест. Необходимо проверить лежит ли проекция точки D левее, правее, выше или ниже проекции каждой вершины треугольника. Если да, то точка D лежит снаружи.
Поиск пересечения со сферой
Для нахождения точки пересечения луча, заданного уравнением
которое можно записать в виде:
со сферой, заданной уравнением:
нужно подставить в уравнение сферы вместо x, y и z соответствующие уравнения луча. После раскрытия всех скобок и приведения подобных мы получим квадратное уравнение относительно параметра t.
Если дискриминант квадратного уравнения меньше нуля, то луч и поверхность второго порядка общих точек пересечения не имеют. В противном случае можно будет вычислить два значения параметра t. Дискриминант может быть равен нулю — это соответствует предельному случаю касания луча поверхности, и мы получим два совпадающих значения параметра t.
Для нахождения координат точек пересечения луча и поверхности достаточно подставить найденные значения параметра t в уравнения луча (2.17).
В программе при нахождении двух пересечений для визуализации выбирается ближнее из них. Ближнее пересечение определяется путем сравнения найденных параметров t. Ближе к точке наблюдения находится то пересечение, которому соответствует меньший параметр t.
Если одно или оба значения параметра t получились отрицательными, это означает, что точка пересечения лежит «сзади» относительно точки начала луча, на половине прямой, находящейся «по нашу сторону» относительно картинной плоскости. Такие точки при поиске пересечения отбрасываются.
Нормальный вектор плоскости, координаты нормального вектора плоскости
Существует ряд заданий, которым для решения необходимо нормальный вектор на плоскости, чем саму плоскость. Поэтому в этой статье получим ответ на вопрос определения нормального вектора с примерами и наглядными рисунками. Определим векторы трехмерного пространства и плоскости по уравнениям.
Нормальный вектор плоскости – определение, примеры, иллюстрации
Чтобы материал легко усваивался, необходимо предварительно изучить теорию о прямой в пространстве и представление ее на плоскости и векторы.
Пример 2
Определить координаты направляющих векторов заданной плоскости x + 2 z — 7 = 0 .
По условию имеем, что дано неполное уравнение плоскости. Чтобы увидеть координаты, необходимо преобразовать уравнение x + 2 z — 7 = 0 к виду 1 · x + 0 · y + 2 z — 7 = 0 . Отсюда получим, что координаты нормального вектора данной плоскости равны ( 1 , 0 , 2 ) . Тогда множество векторов будет иметь такую форму записи ( t , 0 , 2 · t ) , t ∈ R , t ≠ 0 .
Ответ: ( t , 0 , 2 · t ) , t ∈ R , t ≠ 0 .
При помощи уравнения плоскости в отрезках, имеющего вид x a + y b + z c = 1 , и общего уравнения плоскости возможна запись нормального вектора этой плоскости, где координаты равны 1 a , 1 b , 1 c .
Знания о нормальном векторе позволяют с легкостью решать задачи. Часто встречающимися задачами являются задания с доказательствами параллельности или перпендикулярности плоскостей. Заметно упрощается решение задач на составление уравнений заданной плоскости. Если имеется вопрос о нахождении угла между плоскостями или между прямой и плоскостью, то формулы нормального вектора и нахождения его координат помогут в этом.
Как посчитать нормаль
Нормалью грани (face normal) называется вектор, определяющиий ориентацию лицевой грани многоугольника (рис. 5.1).

Рис. 5.1. Лицевая нормаль поверхности
Нормали вершин (vertex normals) основаны на той же самой идее, но в этом случае задается не нормаль для всего многоугольника, а отдельная нормаль для каждой образующей его вершины (рис. 5.2).

Рис. 5.2. Нормали вершин поверхности
Direct3D необходимо знать нормали вершин, поскольку они необходимы чтобы оперделить под каким углом свет падает на грань. Кроме того, поскольку вычисление освещенности выполняется для каждой из вершин, Direct3D необходимо знать ориентацию грани (нормаль) для каждой вершины. Обратите внимание, что нормаль вершины не всегда совпадает с нормалью грани. Наиболее распростарненным примером объекта у которого нормали треугольных граней не совпадают с нормалями вершин является сфера или цилиндр (рис. 5.3).

Рис. 5.3. Пример объекта, у которого нормали вершин не совпадают с нормалями граней. Векторы нормалей вершин выделены черным цветом, а векторы нормалей граней — серым
Для описания нормалей вершин нам необходимо добавить соответствующие члены в структуру данных вершины:
struct Vertex < float _x, _y, _z; float _nx, _ny, _nz; static const DWORD FVF; >const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL;
Обратите внимание, что мы убрали члены данных, задающие цвет вершины, которые использовали в предыдущей главе. Дело в том, что теперь для вычисления цвета вершин мы будем использовать данные освещения.
Для простых объектов, таких как кубы и сферы, нормали вершин можно оперделить путем осмотра. Для сложных сеток необходим более алгоритмизированный способ. Предположим, что треугольник образован вершинами p 0, p 1 и p 2, и нам необходимо вычислить нормали n 0, n 1 и n 2 для каждой из вершин.
Простейший подход заключается в том, чтобы вычислить нормаль грани для треугольника и использовать ее в качестве нормали для всех трех вершин. Сперва вычислим два вектора, лежащих в полскости треугольника:
Тогда нормаль грани вычисляется по формуле:
Поскольку нормаль каждой вершины совпадает с нормалью грани:
Ниже приведена функция, которая вычисляет нормаль треугольной грани на основании координат трех ее вершин. Обратите внимание, что функция предполагает, что вершины перечислены по часовой стрелке. Если это не так, нормаль будет указывать в противоположном направлении.
void ComputeNormal(D3DXVECTOR3* p0, D3DXVECTOR3* p1, D3DXVECTOR3* p2, D3DXVECTOR3* out)
Использование нормали грани в качестве нормалей вершин не позволяет добиться гладкого изображения состоящих из треугольных граней сложных кривых поверхностей. Лучшим методом вычисления нормалей вершин является усреднение нормалей (normal averaging). Чтобы вычислить вектор нормали v n для вершины v , мы вычисляем нормали граней всех треугольников сетки, в которые входит данная вершина v . Затем вектор нормали вершины v n получается путем вычисления среднего значения всех этих нормалей граней. Давайте разберем конкретный пример. Предположим, вершина v входит в три треугольника, для которых известны их нормали граней n 0, n 1 и n 2. Тогда v n вычисляется путем усреднения нормалей граней:
В процессе преобразований может получиться так, что векторы нормалей станут денормализованными. Так что лучше всего предусмотреть возможность подобной ситуации и приказать Direct3D заново нормализовать все векторы нормалей после преобразований, включив режим визуализации D3DRS_NORMALIZENORMALS:
Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);