Форум: "Игры";
Текущий архив: 2004.11.07;
Скачать: [xml.tar.bz2];
ВнизДвижение объектов в OpenGL или как замерять время Найти похожие ветки
← →
ПсихЪ_копия (2004-07-11 10:47) [0]Столкнулся с такой проблемой:
Делаю:
step := Speed*( GetTickCount()-LastTime )/1000;
// step - шаг, на который изменится координата за текущий кадр (для плавного движения объекта)
// Speed - количество пикселей, которые проходит объект за секунду
// LastTime - последнее значение GetTickCount(), считаю в конце цикла отрисовки
В этоге движение осуществляется не плавно, а какими-то рывками, как буд-то step вычисляется в отдельной функции вызываемой через рендомные промежутки времени. Видимо вся проблема в глючности GetTickCount т.к. считаемый с её помощью FPS тоже невероятно прыгает и глючит (тема на счёт прыгающего FPS"а еыт на http://GameDev.ru/Forum/).
Так вот, сосбственно, вопрос - Как нормально замерять время в милличсекундах?
← →
miek © (2004-07-11 12:19) [1]QueryPerformanceCounter
queryperformancefrequency
← →
Zeqfreed © (2004-07-11 12:21) [2]Помоему нужно сначала разделить скорость на 1000 а потом только умножить на разницу во времени. т.е.:
step := (GetTickCount - LastTime) * (Speed/1000);
← →
Zeqfreed © (2004-07-11 12:22) [3]Хотя извиняюсь, сморозил тупость, никакой разницы вроде и нет =)
← →
ПсихЪ_копия (2004-07-11 13:30) [4]Решение нашёл. Хотя скорее всего оно и кривое. Теперь делаю так.
Нахожу плавный, не скачущий FPS:
NowTickCount := GetTickCount();
FPSDelta := FPSDelta + NowTickCount - FPSTickCount;
if NowTickCount <> FPSTickCount then
inc( FPSCnt );
FPSTickCount := NowTickCount;
if FPSDelta >= 500 then
begin
FPSCount := FPSCnt*2;
FPSDelta := 0;
FPSCnt := 0;
end;
Далее, основываясь на этом FPS вычисляю шаг для изменения координат:
step := FPSCount/1000*Speed;
Единственная проблема - первые пол-секунды FPS равен 0 и ничего не движется... Если снижвать с пол-секунды до, скажем, 100 миллисекунд, тогда сильно снижается точность...
Но юзать можно.
← →
Zer0 © (2004-07-12 02:25) [5]GetTickCount() выдает время с точностью ~17мс
при большом fps будут проблемы
← →
NailMan © (2004-07-12 11:14) [6]Совет дня: не используй в играх GetTickCount - это бяка низкого разрешения.
Пользуй для синхро QueryPerformanceCounter как посоветовал miek ©, а вот как использовать расскажу я...
делаем структуру:TSyncronize = packed record
LastHPC : Int64;
TimeOffset : Cardinal;
CorrMultiplier : Extended;
End;
Объявляем глобальные переменные:TimerResolution : Int64; //Разрешение одной секунды в HighPerfomance тиках
TimerMSecResolution : Cardinal; //Разрешение одной миллисекунды
И объявляем процедуры/функции:Procedure SetTimerResolution;
var z,z2:int64;
begin
QueryPerformanceCounter(z);
Sleep(1000);
QueryPerformanceCounter(z2);
TimerResolution:=z2 - z;
TimerMSecResolution:= round(TimerResolution / 1000);
end;
Процедура определяет разрешение HighPerfoance счетчика на конкретной машине и вычисляет разрешение 1-й миллисекунды.
Скажем на большинстве тачер очень разной конфигурации разрешение счетчика было в районе 3.5 млн тиков в секунду.Function SetSync(msecs:Cardinal):TSyncronize;
begin
QueryPerformanceCounter(result.LastHPC);
result.TimeOffset:=TimerMSecResolution * msecs;
Result.CorrMultiplier:=1;
end;
Функция устанавливает стартовое значение синхро и задает время ожидания в миллисекундах.Function CheckSync(Var Sync:TSyncronize):boolean;
var tickcount,subtraction:int64;
begin
result:=false;
QueryPerformanceCounter(Tickcount);
subtraction:=tickcount - Sync.LastHPC;
If subtraction>=Sync.TimeOffset then
begin
If Sync.TimeOffset=0 then Sync.CorrMultiplier:=1 else
Sync.CorrMultiplier:=subtraction / (Sync.TimeOffset);
result:=true;
end;
end;
Функция определяет свершилось ли событие(прошедшее время с момента установки синхро[SetSync-ом]) превысило или равно велечине времени ожидания для этого синхро) и создает коэффициент поправки.
Последний нужен для масштабирования како-го либо процесса, в т.ч. анимаци и движений.
Пример использования:
- У каждого Актера есть свой синхро Sync:TSyncronize;
- При инициализации Актера на сцене ему задается начальное значение синхро. Скажем Actor.Sync:=SetSync(20);
- Когда должны делать обработку процессов Актера(двигаем его или че-то еще с ним творим), то делаем это так:
Procedure TActor.Processing;
begin
if CheckSync(Sync) then
BEGIN
...
...
//roll Rotation
If not RollActive then
MoveCaps.RollAngularVelocity:=MoveCaps.RollAngularVelocity * 0.98
else
MoveCaps.RollAngularVelocity:=MoveCaps.RollAngularVelocity +
MoveCaps.RollAngularAcceleration * Sync.CorrMultiplier * 0.05;
if (MoveCaps.RollAngularVelocity<>0) then
begin
if (MoveCaps.RollAngularVelocity<=-MoveCaps.MaxAngularVelocity) then
MoveCaps.RollAngularVelocity:=-MoveCaps.MaxAngularVelocity;
if (MoveCaps.RollAngularVelocity>=MoveCaps.MaxAngularVelocity) then
MoveCaps.RollAngularVelocity:=MoveCaps.MaxAngularVelocity;
end;
...
...
Sync:=SetSync(20);
END;
Итого получаем полностью синхронизированные с производительностью машины движения. На убогих тачках коэффициент будет больше единицы и движение будет более "растянутым" по значению, а на нормальной тачке коэффициент будет близок к единице.
---
WBR, NailMan aka 2:5020/3337.13
← →
Колбасьев © (2004-07-12 11:52) [7]>> Единственная проблема - первые пол-секунды FPS равен 0 и
>> ничего не движется... Если снижвать с пол-секунды до, скажем,
>> 100 миллисекунд, тогда сильно снижается точность...
Надо первые пол-секунды выводить черный экран ;-)
И все будет смотрется нормально.
← →
ПсихЪ_просто (2004-07-13 13:15) [8]
> NailMan © (12.07.04 11:14) [6]
Огромное спасибо. Тема закрыта.
← →
NailMan © (2004-07-13 15:57) [9]Да кстате насчет подсчета фпс:
предпочитаю мерять фактический ФПС, а не теоретически-"реальный", т.е.
создаю мастдайный счетчик(функцией WinAPI) в котором создается строчка(создавать надо ее именно там так как в Render не должно быть лишний операций таких тяжелых как строковые) с ФПСом на основе глобальной переменной-счетчика. Там же и обнуляется. Время срабатывания 1000мс. Фактически это аналог TTimer, но без формы и рочего батута.
Счетчик инкрементируется в методе движка Render.
Таким образом считается фактическое число кадров отрендеренных за прошедшую секунду.
Что касаемо "быстрых" счетчиков ФПС(показывают хоть робные значения), то имхо это неточное число или так сказать "вероятное", потому что считается за небольшой отрезок секунды и множится на число отрезков в секунде.
Да не спорю - эффектно, но не точно. На сцене за оставшийся промежуток времени может все что угодно и заметно снизить результат. К тому же увеличение числа строковых операций(создание строки с ФПСом будет только хуже для скорости).
Вот так...
---
WBR, NailMan aka 2:5020/3337.13
← →
ПсихЪ_копия (2004-07-13 23:38) [10]
> NailMan © (13.07.04 15:57) [9]
Хм... А как ты выводишь ФПС на экран, не переводя его в строку или там Window.PAnsiChar?
← →
NailMan © (2004-07-14 09:19) [11]ПсихЪ_копия
Да не, я перевожу в строчку, но в обработчике таймера, которая выполняется раз в секунду, а в рендере только используется уже подготовленная String. Тоже самое с стокой информации(скажем можно выводить для дебага координаты чего-то), готовая строчка рендерится, а подготавливается(заполняется) когда игрок поменяет координаты.
---
WBR, NailMan aka 2:5020/3337.13
← →
__?!__ (2004-07-14 10:39) [12]Юзай GLScene, там есть Cadencer.
← →
ПсихЪ_злобный_АПИшник (2004-07-14 15:21) [13]
> __?!__ (14.07.04 10:39) [12]
Приколист... GLScene must die!!! API rulezzz!!!
Страницы: 1 вся ветка
Форум: "Игры";
Текущий архив: 2004.11.07;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.057 c