вторник, 26 января 2016 г.

Математика в скриптах Коута

Всё думал, как лучше показать работу с векторами, волшебными квадратами, кватернионами и углами Эйлера в 3D-Coat... Этой цели хорошо подходит моделирование движения камеры вокруг сцены, но работа с камерой в скриптах будет позже, поэтому делаю простой обзор: наверняка Вы найдёте применение этой математике в своих скриптах.


Объекты математики могут изменять себя или возвращать изменённую копию. Методы, возвращающие копию объекта, заканчиваются на `Copy`. Например, когда ниже написано `normalize[Copy]()`, значит, класс имеет два метода:
  1. normalize() - меняет сам объект
  2. normalizeCopy() - возвращает изменённую копию

Векторы Хэвисайда


Vec3

// конструкторы
// все значения вектора равны 10.1
Vec3  a( 10.1 );
// инициализация XYZ
Vec3  b( 10.1, 20.2, -30.3 );
Vec3  c = { 10.1, 20.2, -30.3 };

// преобразование вектора в строку
auto  sa = string( a );

// проверка состояния
bool  stateN = a.normalized();
bool  stateZ = a.zero();

// получение элементов вектора
float  x = c[ 0 ];
float  y = c[ 1 ];
float  z = c[ 2 ];
// или
float  x = c.x();
float  y = c.y();
float  z = c.z();

// инициализация элементов
a[ 0, Значение ];
a[ 1, Значение ];
a[ 2, Значение ];
// или
a.x( Значение );
a.y( Значение );
a.z( Значение );

// арифметика
auto  negA = -a;
a += b;
a -= b;
a *= c;
a /= c;
a *= 77;
a /= 77;
Vec3  d = a + b;
Vec3  e = a - b;
Vec3  f = a * b;
Vec3  g = a / b;
Vec3  h = a * 77;
Vec3  i = a / 77;
Vec3  j = 77 * a;

// угол между двумя векторами
float  angle = a.angle( b );

// расстояние
float  distance = a.distance( b );

// скалярное произведение
float  dot = a.dot( b );

// длина вектора
float  length = c.length();

// модуль
c.abs();
auto  r = c.absCopy();
// # Далее эти две строки будут показываться как одна в виде:
//   c.abs[Copy]();

// обрезание вектора по длине
// здесь: "не короче 10 и не длиннее 20.5"
c.clamp[Copy]( 10, 20.5 );
// здесь: "ровно 10"
c.truncate[Copy]( 10 );

// векторное произведение
c.cross[Copy]( b );

// выбор макс / мин значения из этого вектора и предложенного
a.max[Copy]( b );
a.min[Copy]( b );

// нормализация вектора
a.normalize[Copy]();

// отражение
a.reflect[Copy]( b );

// преломление
a.refract[Copy]( b, angle );


Матрицы Сильвестра


Mat3

// конструкторы
Mat3  a( 1, 2, 3,
         4, 5, 6,
         7, 8, 9 );
Mat3  b = { 1, 2, 3,
            4, 5, 6,
            7, 8, 9 };

// преобразования матрицы 3x3
auto  sa = Angles( a );
auto  sm = Mat4( a );
auto  sq = Quat( a );
auto  ss = string( a );

// проверка состояния
bool  stateI = a.identity();
bool  stateO = a.orthonormal();
bool  stateS = a.symmetric();
bool  stateZ = a.zero();

// получение элементов матрицы
float  e00 = a[ 0, 0 ];
float  e01 = a[ 0, 1 ];
// ...
float  e22 = a[ 2, 2 ];

// инициализация элементов
a[ 0, 0, Значение ];
a[ 0, 1, Значение ];
// ...
a[ 2, 2, Значение ];

// арифметика
auto  negA = -a;
a += b;
a -= b;
a *= c;
a *= 77;
a /= 77;
Vec3  d = a + b;
Vec3  e = a - b;
Vec3  f = a * b;
Vec3  h = a * 77;
Vec3  i = a / 77;
Vec3  j = 77 * a;

// детерминант
float  determinant = a.determinant();

// трассировка
float  trace = a.trace();

// инверсия
a.invert[Copy]();

// нормализация
a.orthonormalize[Copy]();

// транспонирование
a.transpose[Copy]();

Mat4

// конструкторы
Mat4  a( 1,  2,  3,  4,
         5,  6,  7,  8,
         9, 10, 11, 12 );
Mat4  b = { 1,  2,  3,  4,
            5,  6,  7,  8,
            9, 10, 11, 12 };

Mat3  rotation = { 0, 0, 1,
                   1, 0, 0,
                   0, 1, 0 };
Vec3  translation = { -100, -20, 50 };
Mat4  c( rotation, translation );

Vec3  scaling = { 1, 20, 300 };
Mat4  d( scaling, translation );

// преобразования матрицы 4x4
auto  sm = Mat3( a );
auto  sq = Quat( a );
auto  ss = string( a );

// проверка состояния
bool  stateI = a.identity();
bool  stateO = a.orthonormal();
bool  stateS = a.symmetric();
bool  stateZ = a.zero();

// получение элементов матрицы
float  e00 = a[ 0, 0 ];
float  e01 = a[ 0, 1 ];
// ...
float  e33 = a[ 3, 3 ];

// инициализация элементов матрицы
a[ 0, 0, Значение ];
a[ 0, 1, Значение ];
// ...
a[ 3, 3, Значение ];

// арифметика
auto  negA = -a;
a += b;
a -= b;
a *= c;
a *= 77;
a /= 77;
Vec3  d = a + b;
Vec3  e = a - b;
Vec3  f = a * b;
Vec3  h = a * 77;
Vec3  i = a / 77;
Vec3  j = 77 * a;

// детерминант
float  determinant = a.determinant();

// трассировка
float  trace = a.trace();

// инверсия
a.invert[Copy]();

// транспонирование
a.transpose[Copy]();


Углы Эйлера

// конструкторы
Angles  a( 1, 2, 3 );
Angles  b = { -1.1, 2.2, -3.3 };

// преобразования
auto  sm = Mat3( a );
auto  sn = Mat4( a );
auto  sq = Quat( a );
auto  sa = string( a );

// проверка состояния
bool  stateZ = a.zero();

// получение элементов
float  pitch = a[ 0 ];
float  yaw   = a[ 1 ];
float  roll  = a[ 2 ];
// или
float  pitch = a.pitch();
float  yaw   = a.yaw();
float  roll  = a.roll();

// инициализация элементов
a[ 0, Значение ];
a[ 1, Значение ];
a[ 2, Значение ];
// или
a.pitch( Значение );
a.yaw( Значение );
a.roll( Значение );

// арифметика
auto  negA = -a;
a += b;
a -= b;
a *= 77;
a /= 77;
Vec3  d = a + b;
Vec3  e = a - b;
Vec3  h = a * 77;
Vec3  i = a / 77;
Vec3  j = 77 * a;

// нормализация углов
a.normalize180[Copy]();
a.normalize360[Copy]();


Кватернионы Гамильтона

// конструкторы
Quat  a( 1.1, 2.2, 3.3, 50 );
Quat  b = { 1.1, 2.2, -3.3, 50 };
Quat  c = a * 10;

// преобразования кватерниона
auto  sa = Angles( a );
auto  sm = Mat3( a );
auto  sn = Mat4( a );
auto  ss = string( a );

// проверка состояния
bool  stateN = a.normalized();
bool  stateZ = a.zero();

// получение элементов
float  x = a[ 0 ];
float  y = a[ 1 ];
float  z = a[ 2 ];
float  w = a[ 3 ];
// или
float  x = a.x();
float  y = a.y();
float  z = a.z();
float  w = a.w();

// инициализация элементов
a[ 0, Значение ];
a[ 1, Значение ];
a[ 2, Значение ];
a[ 3, Значение ];
// или
a.x( Значение );
a.y( Значение );
a.z( Значение );
a.w( Значение );

// арифметика
auto  negA = -a;
a += b;
a -= b;
a *= c;
a /= c;
a *= 77;
a /= 77;
Vec3  d = a + b;
Vec3  e = a - b;
Vec3  f = a * b;
Vec3  g = a / b;
Vec3  h = a * 77;
Vec3  i = a / 77;
Vec3  j = 77 * a;

// скалярное произведение
float  dot = a.dot( b );

// длина
float  length = c.length();

// вычисление `w`
c.calcW[Copy]();

// устанавливает `w = 0` и
// меняет знак для `xyz`, если было `w < 0`
a.compress[Copy]();

// сопряжение
a.conjugate[Copy]();

// степень
a.exp[Copy]();

// инверсия
a.invert[Copy]();

// логарифм
a.ln[Copy]();

// нормализация
a.normalize[Copy]();

Представленные выше классы соблюдают принятые для скриптинга соглашения. А именно:

Можно строить цепочки методов.
v.abs().normalize();

Объекты одного класса сравниваются оператором `==`.
if (a == b) ...

При переводе объекта в строку, получаем его состояние в формате JSON.
[10.1, 20.2, -30.3]

Как-то незаконченно получилось... Закончу списком хороших статей, которые наглядно рассказывают о векторах, матрицах и кватернионах. Где список? В этом же абзаце, см. ссылки!) И отличные видео-лекции на закуску: игры и математика.

Комментариев нет: