миллисекунды — обработка цикла обновления с помощью C ++ Chrono?

Я определенно немного растерялся с новой C ++ Chrono библиотекой.

Здесь у меня есть цикл обновления. Он запускает две операции:

engine.Update()
engine.Render()

Это длинные операции, и трудно сказать, как долго они.

Таким образом, мы измеряем, сколько времени они заняли, затем делаем некоторые вычисления и находим лучший способ постепенно вызвать update, прежде чем мы вызовем render.

Для этого я использую функциональность Chrono в C ++ 11. Я выбрал его, потому что это звучало как хорошая сделка: более точный, более зависимый от платформы. Я обнаружил, что сейчас у меня больше проблем, чем сейчас.

Ниже приведен мой код, а также моя основная проблема. Любая помощь в решении проблемы или правильном способе выполнения моих операций, крайне необходима!

Я отметил свои вопросы в комментариях непосредственно рядом с соответствующими строками, которые я повторю ниже.

Заголовочный файл:

class MyClass
{
private:
typedef std::chrono::high_resolution_clock Clock;
Clock::time_point mLastEndTime;
milliseconds mDeltaTime;
}

Упрощенный цикл обновления

// time it took last loop
milliseconds frameTime;
// The highest we'll let that time go. 60 fps = 1/60, and in milliseconds, * 1000
const milliseconds kMaxDeltatime((int)((1.0f / 60.0f) * 1000.0f)); // It's hard to tell, but this seems to come out to some tiny number, not what I expected!
while (true)
{
// How long did the last update take?
frameTime = duration_cast<milliseconds>(Clock::now() - mLastEndTime); // Is this the best way to get the delta time, with a duration cast?
// Mark the last update time
mLastEndTime = Clock::now();

// Don't update everything with the frameTime, keep it below our maximum fps.
while (frameTime.count() > 0) // Is this the best way to measure greater than 0 milliseconds?
{
// Determine the minimum time. Our frametime, or the max delta time?
mDeltaTime = min(frameTime, kMaxDeltatime);

// Update our engine.
engine->Update((long)mDeltaTime.count()); // From here, it's so much easier to deal with code in longs. Is this the best way to shove a long through my code?

// Subtract the delta time out of the total update time
frameTime -= mDeltaTime;
}
engine->Render();
}

Главный вопрос:
Мой mDeltaTime всегда выходит крошечным. Это в основном застряло в почти бесконечном цикле. Это потому, что kMaxDeltatime очень мало, но если я нацеливаюсь на 60 кадров в секунду, я не рассчитал правильные миллисекунды?

Вот все вопросы, перечисленные выше:

const milliseconds kMaxDeltatime((int)((1.0f / 60.0f) * 1000.0f)); // It's hard to tell, but this seems to come out to some tiny number, not what I expected!

frameTime = duration_cast<milliseconds>(Clock::now() - mLastEndTime); // Is this the best way to get the delta time, with a duration cast?

while (frameTime.count() > 0) // Is this the best way to measure greater than 0 milliseconds?

engine->Update((long)mDeltaTime.count()); // From here, it's so much easier to deal with code in longs. Is this the best way to shove a long through my code?

Простите за путаницу, ребята. Я чувствую себя идиотом с этой хронографической библиотекой. Большинство справочных сайтов, справочных материалов или даже самого прямого кода очень запутанно читать и понимать, к чему я их применяю. Указатели на то, как я должен искать решения или код, очень приветствуются!

РЕДАКТИРОВАТЬ:
Йоахим отметил, что std :: min / max отлично работает в течение миллисекунд! Обновлен код для отражения изменений.

8

Решение

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

Ниже приведен ряд конкретных рекомендаций. Для каждой рекомендации я процитирую строки вашего исходного кода, а затем покажу, как мне переписать эти строки.


const milliseconds kMaxDeltatime((int)((1.0f / 60.0f) * 1000.0f)); // It's hard to tell, but this seems to come out to some tiny number, not what I expected!

Нет никаких причин делать такие вычисления с константами ручного преобразования. Вместо этого вы можете сделать:

typedef duration<long,std::ratio<1,60>> sixtieths_of_a_sec;
constexpr auto kMaxDeltatime = sixtieths_of_a_sec{1};

frameTime = duration_cast<milliseconds>(Clock::now() - mLastEndTime); // Is this the best way to get the delta time, with a duration cast?

Вы можете просто сохранить значение в его родном типе:

auto newEndTime = Clock::now();
auto frameTime = newEndTime - mLastEndTime;
mLastEndTime = newEndTime;

while (frameTime.count() > 0) // Is this the best way to measure greater than 0 milliseconds?

Вместо этого используйте:

while (frameTime > milliseconds(0))

engine->Update((long)mDeltaTime.count()); // From here, it's so much easier to deal with code in longs. Is this the best way to shove a long through my code?

Лучше всего написать код, который использует chrono::duration типов, а не использовать универсальные целочисленные типы вообще, но если вам действительно нужно получить универсальный целочисленный тип (например, если вы должны передать long в сторонний API), то вы можете сделать что-то вроде:

auto mDeltaTime = ... // some duration type

long milliseconds = std::chrono::duration_cast<std::duration<long,std::milli>>(mDeltaTime).count();
third_party_api(milliseconds);

Или же:

auto milliseconds = mDeltaTime/milliseconds(1);

И чтобы получить дельту, вы должны сделать что-то вроде:

typedef std::common_type<decltype(frameTime),decltype(kMaxDeltatime)>::type common_duration;
auto mDeltaTime = std::min<common_duration>(frameTime, kMaxDeltatime);
19

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]