Управляем скоростью полета камеры

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

Итак, обозначения:

  • currCameraPos — текущая позиция камеры
  • nextCameraPos — будущая позиция камеры (например на n метров позади объекта наблюдения)
  • speed — скорость камеры в м/с
  • maxDist — максимально допустимая дистанция между currCameraPos и nextCameraPos

Алгоритм:

  • вычисляем направление и длину от текущей до будущей позиций камеры
  • корректируем длину в зависимости от speed и maxDist
  • смещаем камеру из текущей в будущую позицию камеры с учетом длины

А вот, собственно, код этого безобразия:

void updateCameraPosition( float dt )
{
    // Скорость камеры в метрах в секунду
    const float speed = 0.5f;
    // Максимальная дистанция от текущей позиции камеры до будущей
    const float maxDist = 1.0f;

    // Текущая позиция камеры
    const Ogre::Vector3 currCameraPos = camera->getPosition();
    // Будущая позиция камеры
    const Ogre::Vector3 nextCameraPos = calculateCameraPosition();

    // Направление от текущей позиции камеры до будущей
    Ogre::Vector3 direction = nextCameraPos - currCameraPos;
    // Длина смещения камеры
    float dist = direction.length();
    // Нормализуем направление
    direction.normalise();

    // Проверим дистанцию
    if (dist > maxDist)
    {
        camera->setPosition(nextCameraPos - direction * maxDist);
    }
    // Иначе применим скорость
    else
    {
        // Ограничим максимальное смещение, 
        // чтобы не улететь дальше nextCameraPos;
        const float realSpeed = Ogre::Math::Clamp(dt * speed, 0.0f, dist);
        camera->setPosition(currCameraPos + direction * realSpeed);
    }
}

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

Примитивное управление камерой в Ogre3D

Задача: камера должна наблюдать за объектом, быть на расстоянии 5 метров от него и не менее 2.5 метров над землей.

Решение:

void initialise()
{
    // Включаем слежение за объектом
    camera->setAutoTracking(true, target)
}

void update()
{
    // Нормаль направления цели
    Vector3 targetDir = target->getOrientation() * Vector3::UNIT_Z).normalisedCopy();
    // Позиция цели
    Vector3 targetPos = target->getPosition();
    // Позиция камеры
    Vector3 cameraPos = camera->getPosition();
    // Нормаль от цели к камере
    Vector3 targetToCameraDir = (cameraPos - targetPos).normalisedCopy();

    // Ставим камеру в координаты цели
    cameraPos = targetPos;
    // Сдвигаем камеру в направлении targetToCameraDir на 5 метров
    cameraPos += 5.0f * targetToCameraDir;
    // Регулируем высоту камеры
    cameraPos.y = std::max(2.5f, cameraPos.y);

    // Обновляем позицию камеры
    camera->setPosition(cameraPos);
}
Блог Евгения Жирнова