Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Игры";
Текущий архив: 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.036 c
1-1098134528
TechnoDreamer
2004-10-19 01:22
2004.11.07
Обработка onClick при DragMode:=dmAutomatic


1-1098328595
Mitka
2004-10-21 07:16
2004.11.07
Как удалять динамически создаваемые кнопки?


1-1098340108
__dmitry
2004-10-21 10:28
2004.11.07
Run time error 216


1-1098806958
Bogdan
2004-10-26 20:09
2004.11.07
Rave компоненты


1-1098430341
seregin2
2004-10-22 11:32
2004.11.07
NetSend





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский