Фигуры Лиссажу для анимации оружия

Оружие в шутерах от первого лица не должно быть прибито к камере гвоздями – оно раскачивается в такт ходьбе, да и при стоянии на месте медленно ходит туда-сюда из-за постоянного движения рук. Конечно, довольно трудно сымитировать этот эффект в полном соответствии с реальностью, но можно обойтись дешевым и убедительным фейком. Оружие можно двигать вдоль кривой Лиссажу: x = sin(t), y = cos(2t). В результате получается траектория, изображенная на рисунке справа.

Vector2f lissajousCurve(float t)
{
    return Vector2f(sin(t), cos(2 * t));
}

//...

if (playerWalking)
    t += 10.0f * delta;
else
    t += 1.0f * delta;
    
if (t > 2 * PI)
    t = 0.0f;
    
Vector2f p = lissajousCurve(t) / 10.0f;
weapon.localPos = Vector3f(p.x, p.y, 0.0f);

Обновление dlib

Состоялось серьезное обновление набора библиотек dlib. В числе нововведений:

  • Появилась начальная поддержка быстрого преобразования Фурье (FFT) в dlib.image. Возможна фильтрация и свертка изображений (со стороной 2^n) в частотной области;
  • Обновлен пакет dlib.math, добавлена реализация комплексных и дуальных чисел, а также внесены исправления и дополнения в dlib.math.matrix3x3 и dlib.math.matrix4x4;
  • Обновлен пакет dlib.geometry, добавлен класс ориентированных боксов (OBB), трехмерных треугольников и полигональных мешей. Реализована проверка на пересечение между сферой и треугольником, а также сферой и OBB. Добавлен модуль dlib.geometry.bezier с реализацией кривых Безье.

Иллюстрация FFT-свертки: быстрое синтетическое боке (оптическое размытие):

Изменения доступны в ревизии r21 и выше. В ближайшем будущем ожидается первый релиз проекта.

http://code.google.com/p/dlib/

Обновление dlib

Была значительно обновлена коллекция библиотек dlib: добавлены новые модули в пакет geometry (реализация AABB и сфер, а также пересечений между ними), исправлен баг с нахождением обратной матрицы 4×4, добавлен модуль dlib.math.matrix3x3, а также несколько полезных функций для векторов, матриц и кватернионов. Изменения доступны в ревизии r12 и выше.

http://code.google.com/p/dlib/

Эффект затенения

«Честные» динамические тени в аркадных 3D-играх не всегда бывают уместны. Как правило, разработчики ограничиваются статическими предрассчитанными тенями от неподвижных объектов и простым темным кружочком на земле под персонажем – дешево и сердито =)  Я решил дополнить этот нехитрый метод одной простой, но важной деталью: изменение яркости персонажа в зависимости от его местоположения – в тени или на свету. 

Цвет для яркости будет считываться из карты освещения, в которой «запечены» все статические тени на карте.

Допустим, у вас есть некий блок кода, в котором вы находите точку на поверхности полигона под ногами персонажа:

// Проверяем факт пересечения
IntrStatus istatus = character.downRay.intersectTriangle(tri);
if (istatus.hit)
{
  // Извлекаем точку пересечения
  Vector3f ipt = istatus.intersectionPoint;  
  
  if (ipt.y > currentFloorHeight)
  {
    currentFloorHeight = ipt.y;
    
    // Берем материал полигона
    Material mat = materialByIndex[tri.matIndex];
    
    // Если нет карты освещения (текстура 1), то ничего не делаем
    if (mat.textures[1])
    {
      // Берем изображение карты освещения
      Image lightmap = imageByIndex[mat.textures[1].imgIndex];
      
      // Находим текстурные координаты точки пересечения
      Vector2f tc = triObjSpaceToTexSpace(tri.vertices, tri.texCoords2, ipt);
      
      // Конвертируем текстурные координаты в дискретные
      uint imgX = cast(uint)(tc.x * lightmap.width - 0.5f);
      uint imgY = cast(uint)(tc.y * lightmap.height - 0.5f);
      
      // Считываем цвет пикселя c карты освещения
      Color lumel = lightmap[imgX, imgY];
      
      // Применяем полученный цвет к материалу персонажа
      chMaterial.ambientColor = lumel;
      chMaterial.diffuseColor = lumel;
      chMaterial.specularColor = lumel;
    }
  }
}

Осталось определить функцию triObjSpaceToTexSpace. Она будет использовать барицентрические координаты:

Vector2f triObjSpaceToTexSpace(
  Vector3f[3] vertices, 
  Vector2f[3] texCoords, 
  Vector3f point)
{ 
  Vector3f v0 = vertices[2] - vertices[0];
  Vector3f v1 = vertices[1] - vertices[0];
  Vector3f v2 = point - vertices[0];

  float dot00 = dot(v0, v0);
  float dot01 = dot(v0, v1);
  float dot02 = dot(v0, v2);
  float dot11 = dot(v1, v1);
  float dot12 = dot(v1, v2);

  float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
  float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
  float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
      
  Vector2f t2 = texCoords[1] - texCoords[0];
  Vector2f t1 = texCoords[2] - texCoords[0];

  return texCoords[0] + t1 * u + t2 * v;
}