2016-04-20 16 views
3

derzeit im Versuch, glatte Animation Effekt über hardwarebeschleunigte Technik (DirectX oder OpenGL) zu entwickeln, mein derzeitiges Ziel ist sehr einfach, ich möchte Textur von Punkt A bewegen B in bestimmten Dauer zu zeigen, ist diese klassische Art und Weise Objekte zu animieren,SDL2 Glatte Textur (Sprite) Animation zwischen Zeitpunkten Funktion

ich viel über Robert Penner Einschübe lesen, und zu diesem Zweck würde ich mag meine Textur in simpliest linearer Interpolation animieren, wie hier beschrieben: http://upshots.org/actionscript/jsas-understanding-easing

Alles funktioniert, außer dass meine Animation nicht glatt ist, ist es ruckelnd. Der Grund nicht Framedropping wird, ist es einige doppelte Rundungs ​​Aspekte in int,

i in C sehr kurze Probe hergestellt ++ und SDL2 lib dieses Verhalten zu zeigen:

#include "SDL.h" 

//my animation linear interpol function 
double GetPos(double started, double begin, double end, double duration) 
{ 
    return (end - begin) * (double)(SDL_GetTicks() - started)/duration + begin; 

} 

int main(int argc, char* argv[]) 
{ 
    //init SDL system 
    SDL_Init(SDL_INIT_EVERYTHING); 

    //create windows 
    SDL_Window* wnd = SDL_CreateWindow("My Window", 0, 0, 1920, 1080, SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS); 

    //create renderer in my case this is D3D9 renderer, but this behavior is the same with D3D11 and OPENGL 

    SDL_Renderer* renderer = SDL_CreateRenderer(wnd, 0, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_PRESENTVSYNC); 

    //load image and create texture 
    SDL_Surface* surf = SDL_LoadBMP("sample_path_to_bmp_file"); 

    SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer, surf); 

    //get rid of surface we dont need surface anymore 
    SDL_FreeSurface(surf); 

    SDL_Event event; 
    int action = 0; 
    bool done = false; 

    //animation time start and duration 
    double time_start = (double) SDL_GetTicks(); 
    double duration = 15000; 

    //loop render 
    while (!done) 
    { 
     action = 0; 
     while (SDL_PollEvent(&event)) 
     { 
      switch (event.type) 
      { 
      case SDL_QUIT: 
       done = 1; 
       break; 
      case SDL_KEYDOWN: 
       action = event.key.keysym.sym; 
       break; 
      } 
     } 

     switch (action) 
     { 
     case SDLK_q: 
      done = 1; 
     default: 
      break; 
     } 

     //clear screen 
     SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); 
     SDL_RenderClear(renderer); 

     //calculate new position 
     double myX = GetPos(time_start, 10, 1000, duration); 

     SDL_Rect r; 

     //assaign position 
     r.x = (int) round(myX); 
     r.y = 10; 
     r.w = 600; 
     r.h = 400; 

     //render to rendertarget 
     SDL_RenderCopy(renderer, tex, 0, &r); 

     //present 
     SDL_RenderPresent(renderer); 


    } 

    //cleanup 
    SDL_DestroyTexture(tex); 
    SDL_DestroyRenderer(renderer); 
    SDL_DestroyWindow(wnd); 


    SDL_Quit(); 

    return 0; 
} 

Ich nehme an, dass abgehackt Animationseffekt ist im Zusammenhang mit meiner GetPos (...) -Funktion, die mit Doppelwerten arbeitet, und im Rendern über int-Werte. Aber ich kann nicht in doppelter Darstellung rendern, weil ich offensichtlich nicht bei 1,2px zeichnen kann, Meine Frage ist: Kennen Sie irgendeine Technik oder haben Sie einen Rat, wie man diese Art von Animationen (von, bis, Dauer) macht glatt ohne ruckartigen Effekt? Ich bin sicher, dass auf jeden Fall möglich ist, weil Frameworks wie WPF, WIN_RT, Cocos2DX, AndroidJava alle ihnen diese Art von Animationen unterstützt und Textur/Objektanimation ist glatt, Dank im Voraus

bearbeiten per @genpfault Anfrage in

rx: 12 myX: 11.782 
rx: 13 myX: 13.036 
rx: 13 myX: 13.366 
rx: 14 myX: 14.422 
rx: 16 myX: 15.544 
rx: 17 myX: 16.666 
rx: 18 myX: 17.722 
rx: 19 myX: 18.91 
rx: 20 myX: 19.966 
rx: 21 myX: 21.154 
rx: 22 myX: 22.21 
rx: 23 myX: 23.266 
rx: 24 myX: 24.388 
rx: 25 myX: 25.444 
rx: 27 myX: 26.632 
rx: 28 myX: 27.754 
rx: 29 myX: 28.81 
rx: 30 myX: 29.866 
rx: 31 myX: 30.988 
rx: 32 myX: 32.044 
rx: 33 myX: 33.166 
rx: 34 myX: 34.288 
rx: 35 myX: 35.344 
rx: 36 myX: 36.466 
rx: 38 myX: 37.588 
rx: 39 myX: 38.644 

letzte Aktualisierung/lösen:

    Kommentare im Rahmen von x-Positionswerte, wie int und double Zugabe Rahmen
  1. Ich änderte Fragetitel von DirectX/OpenGL zu SDL2, weil Problem mit SDL2 es selbst,
  2. Ich markierte Rafael Bastos Antwort als richtig, weil er mich in die richtige Richtung stieß, Problem wird verursacht durch SDL übertragen die Rohrleitung, die basiert int Genauigkeitswerte
  3. Wie wir oben sehen können, wird das Stottern durch unregelmäßige X-Werte verursacht, die vom Float-Wert gerundet werden. Um dieses Problem zu lösen, musste ich SDL2 Render-Pipeline zu Floats anstelle von Ganzzahlen ändern
  4. Interessant ist, dass SDL2 intern für OpenGL, OpenGLES2, D3D9 und D3D11 Renderer Floats verwendet, aber öffentliche SDL_RenderCopy/SDL_RenderCopyEx API basiert auf SDL_Rect und int Werte, dies verursacht ruckelt Animationseffekte, wenn Animation auf Interpolationsfunktion basiert,

Was genau ich in SDL2 geändert ist weit weit beyound Stackoverflow Umfang, aber in nächsten Schritten writed ich einige Hauptpunkte, was getan werden sollte Animation zu vermeiden Stottern:

  1. Ich habe SDL_FRect und SDL_FPoi verschoben nt structs von internem sys_render api zu render.h api, um sie öffentlich zu machen
  2. Ich erweiterte die aktuellen SDL-Methoden in rect.h/rect.c, um SDL_FRect und SDL_FPoint zu unterstützen, zB SDL_HasIntersectionF (...), SDL_IsEmptyF (...)) SDL_IntersectRectF (...)
  3. i hinzugefügt neue Methode GerRenderViewPortF basierend auf GetRenderViewPort Schwimmers Präzision zu unterstützen
  4. i 2 hinzugefügt neue Methode SDL_RenderCopyF und SDL_RenderCopyFEx zu vermeiden irgendwelche Zahlen Rundung und übergeben realen schwimmt Werte internen Renderer,
  5. alle öffentlichen Funktionen widerspiegeln müssen in dyn_proc SDL api, erfordert es einige SDL-Architektur Wissen, um dies zu tun,
  6. SDL_GetTick() und andere Timing Präzisionsprobleme zu vermeiden, entschied ich mich, meine Interpolation Schritt von Zeit zu Frame-Abhängigkeit zu ändern. Zum Beispiel Animation Dauer im berechnen nicht verwenden:

    float start = SDL_GetTicks(); 
    float duration = some_float_value_in_milliseconds; 
    

    ersetzt ich das:

    float step = 0; 
    float duration = some_float_value_in_milliseconds/MonitorRefreshRate 
    

    und jetzt Schritt im, Inkrementieren ++ nach jedem Rahmen machen
    natürlich hat es einige Nebenwirkungen, wenn mein Engine wird einige Frames fallen, dann ist meine Animationszeit nicht gleich Dauer, weil mehr Frame abhängig ist, natürlich diese Dauer Berechnungen sind nur gültig, wenn VSYNC ON ist, ist es nutzlos, wenn Vblank ausgeschaltet ist,

und jetzt habe ich wirklich glatt und ruckartig frei Animationen, mit Timeline-Funktionen,
@genpfault und @RafaelBastos Dank für Ihre Zeit und für Ihre Ratschläge,

+0

Können Sie eine Sequenz von 'myX'- und' r.x'-Werten erfassen, wenn es ruckelt und diese in die Frage einfügt? – genpfault

+0

sicher, nachbearbeitete und hinzugefügt Probe 20 geloggte Werte – Jakub

+0

Scheint irgendeine Kombination von 'USE_PERFCOUNTER' &' USE_OPENGL' on/off auf [dies] (http://pastebin.com/FRp5bCgn) glatt? – genpfault

Antwort

1

scheint, dass Sie von SDL_GetTicks()

begann zu subtrahieren brauchen

Etwas wie folgt aus:

(end - begin) * ((double)SDL_GetTicks() - started)/duration + begin 

(end - begin) gives you the total movement 

(SDL_GetTicks() - started)/duration gibt Ihnen die Interpolation-Verhältnis, das durch die Gesamtbewegung multipliziert wird Ihnen die amou nt interpoliert, die zum Anfangsteil summiert werden muss, so können Sie die absolut interpolierte Position haben

Wenn das nicht ist, dann ist es wahrscheinlich ein Rundungsproblem, aber wenn Sie nur mit Int-Genauigkeit rendern können, dann I Ich denke, Sie müssen SDL umgehen und es mit einfachen Opengl oder DirectX-Aufrufe, die Floating-Präzision ermöglichen.

+0

danke für die Antwort, das ist mein Fehler in meinem Beispiel natürlich sollte es SDL_GetTicks() - gestartet, und ich habe bereits meinen Beitrag bearbeitet, aber die Animation ist immer noch ruckartig, weil dies eine Art von Zahlen Rundungsfrage ist, und ich suche einige Technik, wie verdoppelt zu int zu berechnen, um ruckartige Animation zu vermeiden – Jakub