Основы 3D – Векторной Графики

Когда мы говорим о 3D, то практически всегда имеем в виду 3D- Векторную Графику. 3D- Растровая Графика существует только в экзотических приложениях для медицины, исследований материалов и геологии, но не используется в Играх и прочих визуальных Развлечениях. Соответственно название лекции "3D-Векторная Графика" можно легко сократить до - "3D-Графика".

Расширение 2D-x,y-координат через z-координату

Каждая вершина Полигона получает дополнительно к его x- и y-координатам еще одну z-координату. В этом смысле, 2D-Векторная Графика - это частный случай 3D-Векторной Графики, при котором все z-координаты равны 0.0f.

Пример расширения функций Scroll, Zoom и Rotate из 2D в 3D:
double arcus = alpha * 2.0 * Math.PI / 360.0;
float cosinus = (float)Math.Cos( arcus );
float   sinus = (float)Math.Sin( arcus );
for ( i=0; i<n; i++ )
{ p[i].X += dx;
  p[i].Y += dy;
  p[i].Z += dz;    //новое измерение
  p[i].X *= zoomx;
  p[i].Y *= zoomy;
  p[i].Z *= zoomz; //новое измерение
  float help = p[i].X * cosinus - p[i].Y * sinus;
  p[i].Y     = p[i].X * sinus + p[i].Y * cosinus;
  p[i].X = help; //Rot-operation around the z-axis doesn't change
}

Scroll и Zoom приобретают в 3D по одной строке Z-строке, 2D-Rotation остается идентична в 3D без Z-строки. Причина: вращение в x,y-Плоскости - это вращение вокруг оси параллельно оси-Z. При таком вращении, все вершины сохраняют свои z-координаты, а меняются только их x- и y- координаты.

Направление оси Z может указывать относительно плоскости x,y, как вперед, так и назад. Таким образом определяются две координатные системы, что создает много путаницы. По умолчанию в DirectX и OpenGL ось Z указывает вперед относительно x,y-плоскости монитора = Лева рукая декартова система координат = x-ось слева направо, y-ось снизу вверх, z-ось спереди назад. Больше информации тут - 3-D Coordinate Systems

Вращение в трех осях: Roll (Крен), Pitch (Тангаж), Yaw (Рыскание)

В 3D появляются новые, в 2D неизвестные вращения, - вокруг оси-x и оси-y. Таким образом, в 3D известно не один способ вращения, а три способа - каждый со своим именным углом, названным по морской/авиационной традиции:
Roll = Крен = вращение по оси-x (по ходу движения);
Pitch = Тангаж = вращение по оси-y;
Yaw = Рыскание = вращение по оси-z;

Осторожно: во вселенной DirectX - в функции RotationYawPitchRoll оси передаются в другой последовательности  y, x, z, как и соответствующие им углы: http://msdn.microsoft.com/en-us/library/bb281744.aspx

В 2D существует только Yaw-угол, который чаще называется alpha.


см: roll-pitch-yaw

Vertex и Vektor

Определения Vertex и Vektor близки по значению. Оба используют аналогичную структуру данных типа { float X; float Y; float Z; }. Однако, существуют определенные интуитивные различия между этими понятиями.
Интуитивная интерпретация Вертекса (Вершины) - это точка в пространстве, похожая на звезду в космосе. Массив Вертксов соответственно можно представить, как облако звёзд.
Плюс - простота. Минус - нет возможности использовать векторные вычисления.
Интуитивная интерпретация Вектора - это стрела с началом в нулевой точке координат (0,0,0), указывающая своим острием на точку (x,y,z) в пространстве. Массив Векторов можно представить, как букет из стрел, имеющих одно начало (0,0,0) и указывающих на различные точки в пространстве. Каждая стрела умеет пространственный угол и длину.
Плюс - Вектора можно складывать, вычитать и умножать. Минус - сложнее для понимания, чем Вертекс.

1) Векторное сложение   : v0 + v1 = { v0.X+v1.X, v0.Y+v1.Y, v0.Z+v1.Z }  v1 садится на острие (вершину)  v0 а результирующий вектор указывает от начала  v0 на острие (вершину) v1.
2) Векторное вычитание  : v1 - v0 = { v1.X-v0.X, v1.Y-v0.Y, v1.Z-v0.Z } результирующий Вектор указывает от острия  v0 на острие v1.
3) Скалярное умножение  : v0 * v1 =   v0.X*v1.X +v0.Y*v1.Y +v0.Z*v1.Z = cos(alpha) - получается косинус угла между  v0 и v1, в случае, когда  v0 и v1 имеют длину, равную 1.0.
4) Векторное умножение  :  получается Вектор, перпендикулярный плоскости, в которой лежат  v0 и v1.
v0 x v1 = { v0.Y*v1.Z - v0.Z*v1.Y,
            v0.Z*v1.X - v0.X*v1.Z,
            v0.X*v1.Y - v0.Y*v1.X }

5) Длина  v : Length = Math.Sqrt( v.X2 + v.Y2 + v.Z2 ).

Применения:
Для 1) существует немного вариантов применения в области 3D-Графики (в отличии от Физики).
Через 2) рассчитывается соединительный вектор между вершинами.
Через 3) рассчитывается угол падения света на плоскость = Face = как правило треугольник.
Через 4) рассчитывается нормаль к плоскости = Face = обычно треугольник.
Через 5) рассчитывается длина, а если длина не играет роли, то она приравнивается к 1.0 = нормированный Вектор v = { v.X/Length, v.Y/Length, v.Z/Length}

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

Нормаль

2D-поверхности имеют только лицевую сторону, но в 3D нужно также различать тыльную сторону и общую ориентацию.
3D-поверхности = Faces обычно нуждаются в рассчете нормали = "Face Normal" = перпендикулярный к плоскости вектор. Направление наружу. См: Face and Vertex Normal Vectors.

Расчет нормали треугольника p0,p1,p2:
1) v0 = p0 - p1 // Вектор из p1 в p0
2) v1 = p2 - p1 // Вектор из p1 в p2
3) n0 = векторное произведение v0 и v1 // Нормаль без нормировки
4) Length = Math.Sqrt( n0.X2 + n0.Y2 + n0.Z2 ) // Длина вектора n0
5) n = { n0.X/Length, n0.Y/Length, n0.Z/Length } // Нормированная нормаль

  см: Cross Product Applet
www.phy.syr.edu/courses/java-suite/crosspro.html

Нормаль определяет, где внешняя и где внутренняя сторона треугольника и под каким углом alpha находится поверхность относительно источника света.  Из скалярного произведения нормированной нормали треугольника (Face) и нормированного вектора Света вычисляется  cos(alpha), что определяет интенсивность освещенности (яркость отображения). Face наиболее освещен, когда направление Света совпадает с направлением нормали Фейса (треугольника).

Примеры:

alpha [Grad]030456090120180360
cos(alpha)1.00.870.710.50.0-0.5-1.01.0
Освещенность (Яркость)100%87%71%50%0%0%0%100%


Для определения направления нормали вручную можно использовать метод левой руки - находясь на второй вершине (Вертексе) p[1], направляем большой палец левой руки на первый Вертекс p[0], а указательный на Вертекс  p[2]. Нормаль Фейса будет совпадать с отогнутым перпендикулярно ладони средним пальцем.

В DirectX3D и в OpenGL у каждого Фейса, принято работать не с одной нормалью, а тремя Вертексными нормалями = "Vertex Normal". То есть один треугольник содержит три параллельные "Vertex Normals", что на первый взгляд - избыточно и бессмысленно для одного треугольника.
Однако, когда несколько треугольников образуют объемную фигуру, сводя свои вершины в одну, например на вершине пирамиды, то можно в этой точке посчитать среднюю нормаль, которая будет хорошо представлять данную вершину.
Преимущество такого подхода видно на краях поверхностей, где  треугольники резко сталкиваются друг с другом - вместо резкого скачка цвета (Flat Shading), сглаженные нормали дают мягкий переход - Gouraud-Shading.
  


Shading (затенение) - это метод симуляции глубины сцены через эффект комбинации света и тени.
Gouraud-Shading опубликован в 1971-м году и назван по имени студента Henri Gouraud (произносится: Гуро).
Близкие методы: Phong-Shading, Metal Shading