| Mesaj |
Info autor |
Postat la 11 Aug 2008 23:11:06 Subiect: Animatie independenta de framerate
|
|
|
Deliverance info:
|
Deliverance:
Modul obisnuit in care faceam asta pana acuma era: timer este un obiect de tip CTimePassed. Asta inseamna ca returneaza timpul care a trecut de la ultimul apel GetTime() pana in momentul respectiv, dupa care reseteaza timer-ul. Cod sursă: float dt = timer.GetTime(); UpdateWhatever(dt); Asta inseamna ca timpul care a trecut variaza de la un frame la altul. Pare insa ca acest timp nu o sa varieze foarte mult dar in realitate se intampla sa variaze asa de mult incat obiectul care se misca pe ecran pare ca se opreste putin si apoi se sare dintr-o pozitie in alta. Am verificat si aveam un timp majoritar(nu mediu) de 0.013 secunde returnat de timer.GetTime() insa aveam si destui timpi de 0.0002 secunde si chiar si timpi de 0.026 sec. Va sa zica ceea ce provoca miscarea neuniforma erau variatiile de timp de la un frame la altul. Am testat inlocuind dt cu 0.013, timpul majoritar. Animatia era smooth. Am stat putin si am observat un lucru interesant: desi timpul pentru un frame varia considerabil FPS-ul era aproape constant si varia cu 1-2 frameuri. Asa ca mi-am zis sa folosesc asta. Ca sa aflu timpul mediu cat i-a luat unui frame sa se deseneze si sa se actualizeze am folosit formula: nrFrameuri * timpMediu = 1.0 de aici, timpMediu = 1.0 / nrFrameuri. Am folosit formula asta si se pare ca animatia este uniforma si nu mai sufera de problemele de mai sus. Singurul neajuns este cand se trece de exemplu de la un ecran al jocului la altul. Sa zicem ca vorbim de ecranul1 si ecranul2. Daca ecran1 se deseneaza si actualizeaza la 100fps si se trece apoi la ecran2 care contine o animatie dependenta de timp si care se deseneaza si actualizeaza la 50 fps se va observa ca animatia va misca putin neuniform pana cand fps-ul din ultima secunda devin 100 de la 50. Pare ca solutia ar fi sa updatez FPS-ul nu la fiecare secunda ci la fiecare frame. Voi cum faceti? P.S e ciudat ca nu exista un topic de programare generala, si cum m-am grabit m-am incurcat din nou 
|
Status:
Înregistrat pe: 13 Oct 2006 10:05:37
Vârsta: 25 ani
Mesaje: 253
Locatie: Iasi , Romania
Programator
|
| |
Postat la 12 Aug 2008 01:18:54 Subiect: < fara subiect >
|
|
|
Dark info:
|
Dark:
Ce folosesti pentru GetTime() ala? Cumva QueryPerformanceCounter() pe vreun sistem nefericit pe care nu functioneaza (de exemplu AMD)?
Animatia iti va aparea fragmentat in doua cazuri: - GetTime() nu-ti da timpul corect - ai spike-uri mari si dese in game loop
In ambele cazuri trebuie sa rezolvi problema de baza. Daca incerci s-o cirpesti cu smoothing-ul ala vei obtine o animatie care nu merge exact la viteza la care a fost facuta, ci variaza in functie de ce se petrece pe ecran (apar mai multi inamici sau mai multe particule, alearga oamenii mai incet).
Un timp de 26 ms/frame inseamna 38 de fps, deci n-ar trebui sa vezi fragmentare in animatie. Daca GetTime() e bun, esti sigur ca nu e vreo greseala prin alta parte, de exemplu sa-l limitezi pe undeva pe dt ala intr-un interval arbitrar?
"Am crezut ca esti ceva mai avansat" - Nekitu, 2008 A.D. Autobaza
|
Status:
Înregistrat pe: 12 May 2007 20:12:30
Vârsta: ? ani
Mesaje: 740
Locatie:
Programator
|
| |
Postat la 12 Aug 2008 11:31:58 Subiect: Re:
|
|
|
Deliverance info:
|
Deliverance:
Dark a scris: Ce folosesti pentru GetTime() ala? Cumva QueryPerformanceCounter() pe vreun sistem nefericit pe care nu functioneaza (de exemplu AMD)? Timpul este returnat cu precizie foarte mare, deci problema nu vine de aici. Dark a scris: Animatia iti va aparea fragmentat in doua cazuri: - GetTime() nu-ti da timpul corect - ai spike-uri mari si dese in game loop In ambele cazuri trebuie sa rezolvi problema de baza. Daca incerci s-o cirpesti cu smoothing-ul ala vei obtine o animatie care nu merge exact la viteza la care a fost facuta, ci variaza in functie de ce se petrece pe ecran (apar mai multi inamici sau mai multe particule, alearga oamenii mai incet). Se pare ca am spike-uri mari si dese in game loop. Lucrul asta se intampla o data ce entitatile de pe harta dispar una cate una si datorita faptului ca sistemul de coliziuni are early rejection, uneori se trece si la etapa narrow pentru detectarea colizunilor alteori se executa doar etapa broad. De aici diferente de framerate. Cum pot rezolva aspectul asta astfel incat sa am un fps cat mai constant? Dark a scris: Un timp de 26 ms/frame inseamna 38 de fps, deci n-ar trebui sa vezi fragmentare in animatie. Daca GetTime() e bun, esti sigur ca nu e vreo greseala prin alta parte, de exemplu sa-l limitezi pe undeva pe dt ala intr-un interval arbitrar? Nu cred ca-l limitez pe dt pe undeva...
Ultima editare efectuată de Deliverance pe 12 Aug 2008 11:38:01; 1 editări în total
|
Status:
Înregistrat pe: 13 Oct 2006 10:05:37
Vârsta: 25 ani
Mesaje: 253
Locatie: Iasi , Romania
Programator
|
| |
Postat la 12 Aug 2008 11:53:04 Subiect: Re: Re:
|
|
|
Dark info:
|
Dark:
Deliverance a scris: Timpul este returnat cu precizie foarte mare, deci problema nu vine de aici. Esti sigur? In unele cazuri e destul de dificil sa-ti dai seama cind QPF o ia prin balarii. Ce sistem ai? Deliverance a scris: Se pare ca am spike-uri mari si dese in game loop. Lucrul asta se intampla o data ce entitatile de pe harta dispar una cate una si datorita faptului ca sistemul de coliziuni are early rejection, uneori se trece si la etapa narrow pentru detectarea colizunilor alteori se executa doar etapa broad. De aici diferente de framerate. Cum pot rezolva aspectul asta astfel incat sa am un fps cat mai constant? Totusi, n-ar trebui sa vezi fragmentare in animatii decit daca iti creste timpul per frame peste 40 de ms, adica ai sub 25 de FPS. Din ce-ai scris in primul post rezulta ca ai tot timpul chiar peste 35, deci n-ar trebui sa fie sesizabil. E altceva mai dubios la mijloc. Ca sa nu mai ai scaderi de FPS cind se incarca o entitate noua sau d-astea, trebuie sa incarci in background. In principiu tot timpul de incarcare ar trebui sa se piarda cu operatiile de disc, deci folosesti overlapped IO: http://msdn.microsoft.com/en-us/library/aa365467 (VS.85).aspx ca sa nu stea procesorul dupa disc. Daca la incarcare pierzi timp si parsind datele (XML, formate de mesh-uri care trebuie prelucrate, etc.), modifici formatul astfel incit sa fie cit mai apropiat de imaginea in memorie. Nu exista nici o scuza pentru a folosi poze JPEG sau geometrie stocata ca XML. Dupa ce te asiguri ca jocul atinge framerate-ul dorit in cazul cel mai nasol, ori pui VSync si va merge la frecventa monitorului (sau o subdiviziune intreaga a sa), ori cronometrezi frame-ul si pui la sfirsit un Sleep() cu diferenta dintre timpul maxim si timpul real. In felul asta ai FPS constant chiar daca ai situatii in care collision-ul nu dureaza nimic pentru ca se evita totul din broad phase si asa mai departe.
Ultima editare efectuată de Dark pe 12 Aug 2008 11:55:14; 2 editări în total
"Am crezut ca esti ceva mai avansat" - Nekitu, 2008 A.D. Autobaza
|
Status:
Înregistrat pe: 12 May 2007 20:12:30
Vârsta: ? ani
Mesaje: 740
Locatie:
Programator
|
| |
Postat la 12 Aug 2008 12:39:00 Subiect: Re: Re: Re:
|
|
|
Deliverance info:
|
Deliverance:
Dark a scris: Deliverance a scris: Timpul este returnat cu precizie foarte mare, deci problema nu vine de aici. Esti sigur? In unele cazuri e destul de dificil sa-ti dai seama cind QPF o ia prin balarii. Ce sistem ai? Am un procesor pentium quad core la 2.4ghz, Windows XP. Dark a scris: Dupa ce te asiguri ca jocul atinge framerate-ul dorit in cazul cel mai nasol, ori pui VSync si va merge la frecventa monitorului (sau o subdiviziune intreaga a sa), ori cronometrezi frame-ul si pui la sfirsit un Sleep() cu diferenta dintre timpul maxim si timpul real. In felul asta ai FPS constant chiar daca ai situatii in care collision-ul nu dureaza nimic pentru ca se evita totul din broad phase si asa mai departe. Da, cred ca asa am sa fac.
|
Status:
Înregistrat pe: 13 Oct 2006 10:05:37
Vârsta: 25 ani
Mesaje: 253
Locatie: Iasi , Romania
Programator
|
| |
Postat la 12 Aug 2008 15:10:57 Subiect: < fara subiect >
|
|
|
Sir Game-a-lot info:
|
Sir Game-a-lot:
Animatia daca nu e tick based ar trebui sa mearga smooth pt. diferente asa mici de rendering time intre frameuri. In principiu, animatia trebuie sa se raporteze la un timp complet nelegat de FPS. Cod sursă: QueryPerformanceCounter(&timp1);
EnterGameLoop();
GameLoop()
{
QueryPerformanceCounter(&timp2);
Animate(timp2-timp1);
if(dt>=60)Render();
} Si modifici deplasarea caracterului in functie de timpul absolut, dupa formula din fizica dx = v*dt; Ca sa limitezi la un maxim FPS-ul, e suficient din GameLoop sa apelezi rutina de Render la intervale egale (de ex. doar daca au trecut minim 1000/60 ms). Pt. loading/object creation, astea se evita de obicei in game loop. Se foloseshte mult duplicarea/copierea de obiecte (de ex. in cazul inamicilor) tocmai pt. a nu folosi resurse (CPU) cand acest lucru se poate evita. Iar daca ai nevoie de un sistem in care sa incarci in timpul jocului resurse ai putea folosi si un thread separat, care preluat de un alt core al procesorului ar face respectiva operatie relativ transparenta pt. end user.
Ultima editare efectuată de Sir Game-a-lot pe 12 Aug 2008 15:17:00; 1 editări în total
Nine women working in perfect harmony can't have a baby in 1 month.
|
Status:
Înregistrat pe: 25 Aug 2007 18:20:41
Vârsta: 33 ani
Mesaje: 116
Locatie: Cluj-Napoca
Programator
Zamolxis Interactive
|
| |
Postat la 12 Aug 2008 16:13:49 Subiect: < fara subiect >
|
|
|
Deliverance info:
|
Deliverance:
Hmm... Cred ca am nevoie de putin ajutor pentru ca se pare ca nu am inteles o chestiune. Ceea ce vreau sa fac este sa reduc FPS-ul la un maxim. Asta inseamna ca vreau ca game loop-ul, sa se execute la un interval fix. Sa zicem de 60 de ori pe secunda. Asta inseamna ca functia update se va apela cu dt = 1/60 de 60 de ori pe secunda. Insa obiectul care se misca implementand ideea asta se misca sacadat. Nu e ceea ce imi doresc. Codul arata cam asa: Cod sursă:
void CGameEngine::Update()
{
float amount = 1.0f / 60.0f;
static float remained = 0.0f;
static CTimer timer;
float time = timer.GetTime()+remained;
WHILE (time>=amount)
{
Render();
time -= amount;
}
remained = time;
Nu inteleg ce se intampla cand VSync este on. Atunci am 60fps si animatia e smooth chiar avand acelasi time step ca cel de atunci cand limitez eu manual framerateul. As vrea sa duplic comportamentul situatiei cand VSync este on. Pesemne insa ca fac ceva gresit...
Ultima editare efectuată de Deliverance pe 12 Aug 2008 17:12:16; 1 editări în total
|
Status:
Înregistrat pe: 13 Oct 2006 10:05:37
Vârsta: 25 ani
Mesaje: 253
Locatie: Iasi , Romania
Programator
|
| |
Postat la 12 Aug 2008 17:36:09 Subiect: Re:
|
|
|
Sir Game-a-lot info:
|
Sir Game-a-lot:
Deliverance a scris: Hmm... Cred ca am nevoie de putin ajutor pentru ca se pare ca nu am inteles o chestiune. Ceea ce vreau sa fac este sa reduc FPS-ul la un maxim. Asta inseamna ca vreau ca game loop-ul, sa se execute la un interval fix. Sa zicem de 60 de ori pe secunda. Aici e buba. Nu poti presupune ca poti executa functia Render la momente exacte divizibile cu 1000/60. Datorita faptului ca duratele de randare a unor frameuri difera, uneori mult mai mari alteori mult mai mici decat 1000/60, trebuie sa randezi doar cand deltaT de la momentul cand ai apelat ultima data Render si momentul actual (NOW) este mai mare decat 1000/60 milisecunde. Cu alte cuvinte, poti sa ai un maxim de 60 de fps nu fix 60. Daca faci ceva de genu asta: Inainte de primul frame: Cod sursă:
LARGE_INTEGER m_time_lastcall, m_time_now, m_QPF, m_time_begin;
QueryPerformanceCounter(&m_time_lastcall);
m_time_begin = m_time_lastcall;
QueryPerformanceFrequency(&m_QPF);
...
void CGameEngine::Update()
{
double dt;
QueryPerformanceCounter(&m_time_now);
dt = m_time_now.QuadPart - m_time_lasttime.QuadPart;
dt = dt *1000.0f / m_QPF.QuadPart;
if(dt >= 1000/60)Render();
m_time_lasttime = m_now;
}
Dupa aia tot ce trebuie sa faci e sa ai grija ca animatia sa se modifice dupa un timp global, nelegat de frameuri. De ex. delta_time = m_time_now - m_time_begin; ComputeAnimation(delta_time); Asta impreuna cu solutia de mai sus. Ideea e ca ai 2 sisteme diferite, nu le poti corci. Animatia trebuie sa mearga dupa ceasul de pe mana end-userului  , so to speak, e timp real. La t secunde cu viteza v creatura trebe sa se miste x = t * v unitati. Acuma daca t-ul nu e in incremente suficient de mici (dureaza mult cite un frame) e evident ca o sa ai jerky movements pe ecran, da nu poti evita asta.
Ultima editare efectuată de Sir Game-a-lot pe 12 Aug 2008 17:39:56; 1 editări în total
Nine women working in perfect harmony can't have a baby in 1 month.
|
Status:
Înregistrat pe: 25 Aug 2007 18:20:41
Vârsta: 33 ani
Mesaje: 116
Locatie: Cluj-Napoca
Programator
Zamolxis Interactive
|
| |
Postat la 12 Aug 2008 18:07:54 Subiect: < fara subiect >
|
|
|
raicuandi info:
|
raicuandi:
Noi parcurgem animatiile dupa timpul "elapsed" in secunde, cum e si intuitiv, si nu e nici o problema. Ori e o problema cu timerul, sau cu sistemul de animatii, ori nu folosesti tu libraria aia cum trebuie (cel mai probabil). Poate dai din greseala pe undeva intr-o formula time * time, care nu mai e linear, si "fluctueaza".
Method 2: Move Your Mouse Pointer If you move your mouse pointer continuously while the data is being returned to Microsoft Excel, the query may not fail. Do not stop moving the mouse until all the data has been returned to Microsoft Excel.
|
Status:
Înregistrat pe: 24 Mar 2007 21:02:40
Vârsta: 22 ani
Mesaje: 514
Locatie: Adelaide, Australia
Programator
|
| |
Postat la 12 Aug 2008 20:20:24 Subiect: < fara subiect >
|
|
|
Deliverance info:
|
Deliverance:
Thanks all! Intre timp am dat si peste un articol interesant care descrie fixed step framerate independent animation. Ideea este foarte desteapta si am abordat-o si eu. Articolul este aici: http://www.gaffer.org/game-physics/fix-your-timestepPe scurt ceea ce fac acum este ca actualizez de fiecare data scena cu acelasi time step fixat de mine, adica cu acelasi dt, si fac acest lucru independent de framerate...
Ultima editare efectuată de Deliverance pe 12 Aug 2008 20:25:00; 1 editări în total
|
Status:
Înregistrat pe: 13 Oct 2006 10:05:37
Vârsta: 25 ani
Mesaje: 253
Locatie: Iasi , Romania
Programator
|
| |
Postat la 12 Aug 2008 23:49:54 Subiect: < fara subiect >
|
|
|
Rimio info:
|
Rimio:
Pe thread separat  ? Ai grija cum faci accesarea memoriei si sa te si asiguri ca threadul chiar executa cod de cate ori vrei tu intr-o secunda.
If at first you don't succeed, you fail.
|
Status:
Înregistrat pe: 24 Mar 2007 21:50:44
Vârsta: 23 ani
Mesaje: 800
Locatie: Pitesti, Arges
Programator
|
| |
Postat la 13 Aug 2008 10:24:33 Subiect: < fara subiect >
|
|
|
surreal info:
|
surreal:
Inca un articol ft. bun care puncteaza niste idei nu chiar evidente la prima vedere: http://dewitters.koonsolo.com/gameloop.html
Reality is the single possibility I can't ignore
|
Status:
Înregistrat pe: 21 Jun 2007 16:41:32
Vârsta: 33 ani
Mesaje: 35
Locatie: Cluj
Programator
|
| |