Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.12.03;
Скачать: CL | DM;

Вниз

И опять о плавности...   Найти похожие ветки 

 
HPR   (2006-02-05 21:31) [0]

В общем решил я забить на таймеры и сделал бесконечный цикл (координаты объектов рассчитываются с плавным шагом dt) в надежде, что рывки прекратятся. Но рывки остались :( К примеру, при запущенном и играющем WinAmp-е Zuma работает плавно, а в моей есть рывки. FPS высокий = 85 при включенном vsync. С таймерами такая же фигня...

Что делаете, чтобы добиться плавности?


 
Кефир87 ©   (2006-02-05 22:40) [1]

Может дело в руках? 8)


 
HPR   (2006-02-06 11:16) [2]

Дело-то всегда в руках, поэтому хочется их натренировать с вашей помощью

Вот привожу главный кусок:

  while not NeedToExitGame do
   begin

    TimeNew := timeGetTime;
    delta := (TimeNew-TimeOld)/1000;

    Application.ProcessMessages; // обработка сообщений

    DXInput.Update; // обновление данных ввода

    DXDraw.BeginScene;

    Common.UpdateObjects(delta); // обновление объектов

    Common.RenderObjects; // рендер объектов в главную поверхность

    DXDraw.EndScene;

    DXDraw.Flip;

    TimeOld := TimeNew;

   end;

Что не так?

P.S. Вообще довольно плавно все движется, но опять же при включенном WinAmp рывки...
P.P.S. Использую компонент UnDelphiX с включенным 3D-ускорением


 
XProger ©   (2006-02-06 11:35) [3]

delta := (TimeNew-TimeOld)/1000;
TimeOld := TimeNew;

+ ко всему, точность timeGetTime может быть не менее 20 мс (насколько я помню) Попробуй вместо неё использовать следующий код:
function ENG_time: Integer;
var
 T : LARGE_INTEGER;
 F : LARGE_INTEGER;
begin
 QueryPerformanceFrequency(Int64(F));
 QueryPerformanceCounter(Int64(T));
 Result := Trunc(1000 * T.QuadPart / F.QuadPart);
end;


 
Nic ©   (2006-02-06 11:54) [4]

Я делаю так. Считаю сколько секунд прошло с рендеринга прошедшего кадра до нынешнего. Из этого числа путём преобразований получаю переменную GLOBAL_K. Потом всё что передвигается перемножаю на этот глобальный коэффициент. Получаю FPS независимый рендеринг. Но при резких скачках FPS некоторая грубость перемещений заметна. С WinAmp"ом не экспериментировал.


 
Don Nikola   (2006-02-06 15:27) [5]

2XProgrer:
Точность timeGetTime регулируется с помощью timeBeginPeriod/timerEndPeriod

2HPR:
Я такой loop использовал:
---
procedure UpdateTime;
var
 CurrentTime, Delta: dword;
begin
 CurrentTime:=timeGetTime;
 if not ApplicationActive then
   begin
     LastTickTime:=CurrentTime;
     Exit;
   end;
 if CurrentTime>=LastTickTime then
   Delta:=CurrentTime-LastTickTime else
   Delta:=CurrentTime+($FFFFFFFF-LastTickTime);
 LastTickTime:=CurrentTime;
 Time:=Time+Delta;
 if (Time-LastFPSTime)>=1000 then
   begin
     FPS:=FramesAtLastSecond;
     FramesAtLastSecond:=0;
     LastFPSTime:=Time;
   end;
 if (not LimitFPS)or((Time-LastFrameTime)>=DesiredFrameTime) then
   begin
     if LastFrameProcessed then
       begin
         LastFrameProcessed:=false;
         LastFrameTime:=Time;
         PostMessage(MainWindow,WM_DOFRAME,0,0);
       end;
   end;
end;

procedure MainLoop;
var
 Msg: TMsg;
begin
 PeekMessage(Msg,0,0,0,PM_NOREMOVE);
 while Msg.Message<>WM_QUIT do
   begin
     if PeekMessage(Msg,0,0,0,PM_REMOVE) then
       DispatchMessage(Msg) else
       begin
         UpdateTime;
         Sleep(SleepValue); //Do not use all possible CPU time
       end;
   end;
end;
---
Фрейм отрабатывается в обработчике WM_DOFRAME, который может быть равен WM_APP+1, например.
При SleepValue>=1, программа всеьма скромно пожирает ресурсы CPU.
Единственная проблема - этот код не предполагает наличие VCL, так что использовать этот код просто копипастом нельзя, но представление о методе дает.


 
VolanD666   (2006-02-06 16:19) [6]

Недавно возился с этой проблемой, хорошо попалась статья хорошая и пример к ней. Во-первых, в качестве таймера я использую QueryPerformanceCounter. Во-вторых, для плавности движения при любом приличном FPS необходимо рассчитывать коэффициент, и потом все перемещения на него умножать. Ну а рендерится это все с помощью WM.


 
XProger ©   (2006-02-06 16:58) [7]

VolanD666, кстати, хочешь краштест для своей игрушки?
if Key = ord("E") then for i := 1 to 1000000000 do;
Затем, во время игры, беги на стену и единожды нажми клавишу "E", если руки прямые - сквозь стену не пролетишь :)


 
VolanD666   (2006-02-06 19:04) [8]

Руки оказались кривые... :(


 
VolanD666   (2006-02-06 19:06) [9]

Хм, а почему так? Ведь при нажатии отрисовка не происходит, а значит и положение камеры не обновляется?


 
XProger ©   (2006-02-06 19:35) [10]

К тому моменту как программа "отойдёт" от цикла - dt будет иметь настолько большое значение, что Pos + Speed * dt - окажется далеко за стеной :)

Решение:
1) Трассировка вектора до пересечения со стеной, а там уже со сферой
2) Использовать фиксированный UPS (Updates Per Second) безо всяких dt :)


 
XProger ©   (2006-02-06 19:49) [11]

* 1) Трассировка отрезка %)

А по-второму методу у меня есть примерный код:

function ENG_time: Integer;
var
 T : LARGE_INTEGER;
 F : LARGE_INTEGER;
begin
 QueryPerformanceFrequency(Int64(F));
 QueryPerformanceCounter(Int64(T));
 Result := Trunc(1000 * T.QuadPart / F.QuadPart);
end;

begin
 ups_delta := 10; // 100 обновлений в секунду (в среднем)
 ups_time_old := ENG_time - ups_delta;
 ups_time     := ENG_time;

 if ENG_Init then // Инициализация
   while not eng_isquit do
   begin
     while PeekMessage(msg, 0, 0, 0, PM_REMOVE) do
     begin
       TranslateMessage(msg);
       DispatchMessage(msg);
     end;

     if eng_isquit then
       break;

     Time       := ENG_time;
     Time_Delta := Time - ups_time_old;
     while Time_Delta >= ups_delta do
     begin
       ENG_update; // обновление игры
       dec(Time_Delta, ups_delta);
     end;
     ups_time_old := Time - Time_Delta;
     ENG_render; // отрисовка
   end;
 ENG_Free; // высвобождение ресурсов - завершение работы движка
end;

Также в WndProc

   WM_CLOSE :
     begin
       ENG_Free;
       eng_isquit := True;
     end;

Что-то в этом духе...


 
VolanD666   (2006-02-06 20:02) [12]

Спасибо! :)


 
HPR   (2006-02-06 21:43) [13]

to XProger: Я вызываю timeBeginPeriod(1), так что период= 1 мс. Но QueryPerformanceCounter говорят действительно точнее, попробую использовать...


 
Don Nikola   (2006-02-07 11:43) [14]

2HPR: QueryPerformanceCounter это обертка для rdtsc, и предназначен для замера сверхмалых отрезков времени. Использование QPF для замера-регулирования FPS, все равно что использование лазерного гироскопа для замера крена детского велосипеда.
Плюс ко всему, чисто теоретически, QPF может работать не на всех машинах, но это скорее всего относиться к машинам before-Pentium.


 
VolanD666   (2006-02-07 13:43) [15]

Использование QPC- самый оптимальный вариант. После того, как я поменял у себя GetTickCount() на QPC, движения стали значительно "плавнее" :)


 
HPR   (2006-02-07 21:42) [16]

В общем поставил QueryPerformanceCounter и Sleep. Вроде бы помогло :) Скорее всего дело в Sleep. Видимо система начинала понижать приоритет моей игре, съедавшей 100% проц. времени.. Хотя это все только теория


 
HPR   (2006-02-08 13:45) [17]

Кстати, камрады по цеху, я ведь забыл вас поблагодарить! БОЛЬШОЕ спасибо ;)



Страницы: 1 вся ветка

Текущий архив: 2006.12.03;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.078 c
6-1152787651
Dyakon_Frost
2006-07-13 14:47
2006.12.03
Обработка полученных данных от сервера!


4-1153410020
Alek_1
2006-07-20 19:40
2006.12.03
Как программно включить ActiveDesktop?


6-1152965383
ntsec
2006-07-15 16:09
2006.12.03
DCC


15-1163749228
TohaNik
2006-11-17 10:40
2006.12.03
Вот они, те кто влияет на неокрепшие души.


15-1163179338
Горгер
2006-11-10 20:22
2006.12.03
Почему Орешник не обновляется?