Самый простой вариант через прозрачность, для этого нужно:
1. При отрисовке меню прозрачность всех цветов умножать на переменную прозрачности (она будет от 0.0f полностью прозрачное до 1.0f полностью видимое). В imgui есть встроенная такая переменная ImGui::GetStyle()::Alpha которая управляет прозрачностью всего гуя и есть функция которая возвращает цвет помноженый на эту глобальную прозрачность ImGui::GetColorU32().
2. При открытии/закрытии прибавлять/вычитать из этой переменной (разницу между предыдущим и текущем кадром в секундах, в imgui это IO.DeltaTime) * (скорость появления, например при 1.0f меню будет появляться/исчезать ровно за секунду). Такой вариант будет хорошо работать даже если анимация еще не завершена в одну сторону, а пользователь включил обратную.
Небольшой псевдокод, который может помочь понять идею:
// глобальное состояние
static int anim_dir = 0; // направление анимации: -1 меню исчезает, +1 меню появляется, 0 ничего
static float anim_dur = 1.0f; // длительность цикла анимации в секундах
...
// переключаем ход анимации
if (открыть)
{
anim_dir = +1;
// сделать видимым
}
else if (закрыть)
{
anim_dir = -1;
}
...
// обновляем анимацию
const float anim_step = ImGui::GetIO().DeltaTime * (1.0f / anim_dur);
float& anim_alpha = ImGui::GetStyle().Alpha;
if (anim_dir < 0) // исчезает
{
anim_alpha -= anim_step;
if (anim_alpha < 0.0f) // полностью
{
anim_alpha = 0.0f;
anim_dir = 0;
// скрыть вовсе
}
}
else if (anim_dir > 0) // появляется
{
anim_alpha += anim_step;
if (anim_alpha > 1.0f) // полностью
{
anim_alpha = 1.0f;
anim_dir = 0;
}
}