2013-02-28 17 views
6

Mam aplikację na iPada i rysuję główny widok za pomocą OpenGL i chcę animować moją własną zmianę po obróceniu urządzenia.Niestandardowa animacja zmiany orientacji interfejsu iOS z OpenGL

Należy pamiętać, że ta aplikacja tylko losuje, nie jest ciągle animowana. Również moja scena to (bardzo złożony) rysunek 2D, a nie 3D. Chcę po prostu obracać się wokół środka wyświetlacza podczas zmiany orientacji urządzenia, zachowując prawidłowy współczynnik proporcji.

W tej chwili mam tylko następujący kod:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{ 
    // nothing yet 
} 

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation 
{ 
    IMMainView *mv = (IMMainView *)self.view; 
    [mv createRenderbuffer]; 
    [mv drawView]; 
} 

Właśnie ponownie utworzyć bufor renderowania OpenGL, aby dopasować nową szerokość i wysokość, gdy obrót zakończy.

Domyślne zachowanie systemu iOS wydaje się obracać widok, ale także rozciąga się dziwnie wraz ze zmianą współczynnika kształtu.

Mogę animować parametry rysowania, aby coś lepiej wyglądało podczas przejścia, ale nie rozumiem (1) jak zatrzymać animację mojej warstwy iOS (2) jak ustawić pętlę animacji z tych wywołań metod pasujące do animacji iOS.

Na przykład podczas animacji, czy aktualna szerokość i wysokość widoku zmienia się progresywnie?

Ewentualnym problemem jest także pytanie, kiedy ponownie utworzyć bufor renderowania, ponieważ jeśli bufor OpenGL nie pasuje do granic widoku iOS, proporcje pikseli nie są poprawne, a rysunek wygląda źle.

Każda pomoc zostanie doceniona.

+0

OK Wydaje mi się, że rozumiem część odpowiedzi na moje pytanie, a mianowicie, że muszę po prostu nadal prezentować bufor renderowania podczas zmiany orientacji, aby przejąć kontrolę nad tym, co jest pokazane w domyślnym przypadku. W chwili obecnej przedstawiam go tylko wtedy, gdy muszę zmienić zawartość widoku w zależności od zmiany interfejsu użytkownika. – Robotbugs

Odpowiedz

3

Spędziłem trochę czasu, szukając rozsądnych sposobów, aby zrobić to poprawnie i skończyłem chodząc na najprostszą trasę, która jest po prostu wyczyścić ekran na willRotateToInterfaceOrientation, a następnie renderować nową treść w odpowiednim miejscu w didRotateFromInterfaceOrientation. Po prostu nie wygląda tak źle, a dodatkowa złożoność czegoś lepszego nie jest warta tego IMHO.

Alternatywnie, podczas gdy ja nie iść do tego rozwiązania, najlepszy wynik z animacją, że osiągnięty z nie zbyt dużo pracy było coś takiego:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{ 
    IMMainView *mv = (IMMainView *)self.view; 
    [mv drawBlankScreen]; 

    m_oldviewsize = self.view.bounds.size; 
} 

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration 
{ 
    IMMainView *mv = (IMMainView *)self.view; 

    CGPoint neworigin = mv.origin; 

    neworigin.x += 0.5f*(self.view.bounds.size.width - m_oldviewsize.width); 
    neworigin.y += 0.5f*(self.view.bounds.size.height - m_oldviewsize.height); 

    mv.origin = neworigin; 

    [mv createRenderbuffer]; 
    [mv drawView]; 
} 

Zmiana pochodzenia jest przeznaczone do ponownego wyśrodkować rysunek poobrotowy w tym samym miejscu, w którym znajdował się przed rotacją.

Znalazłem, że willAnimateToInterfaceOrientation jest wywoływane raz po obliczeniu nowych granic widoku. Dlatego ustawiam nowy bufor renderowania w tym momencie, ponieważ zniekształcenie związane ze zmianą aspektu nie jest tak zauważalne, jak w moim oryginalnym przypadku. Musiałem również wyczyścić ekran w willRotateToInterfaceOrientation, ponieważ występuje opóźnienie, w którym zniekształcona wersja oryginalnego rysunku jest wyraźnie widoczna.

Wadą tego jest to, że czyszczenie ekranu powoduje lekkie błyśnięcie na początku animacji, a także zniekształcenie rozciągające jest nadal obecne, ale zbiegają się na prawidłowym wyglądzie, nie odbiegając od starego wyglądu, po którym następuje skok do nowego wyglądu, więc nie wygląda tak źle. Podejrzewam, że jakakolwiek próba rzeczywistego śledzenia zmian proporcji animacji widoku z aktualizowaniem za pomocą funkcji rysowania w celu ciągłego utrzymywania prawidłowego wyglądu byłaby dość skomplikowana do wdrożenia i prawdopodobnie będzie bardzo podatna na zmiany w Apple w przyszłości.

0

Można obracać wyjście OpenGL w vertex shader następująco:

#version 300 es 


in vec4 position; 
in mediump vec4 texturecoordinate; 

in vec4 color; 

uniform float preferredRotation; 

out mediump vec2 coordinate; 

void main() 
{ 
    //const float pi = 4.0 * atan(1.0); 
    //float radians = ((-90.0)/180.0 * pi); 

    // Preferred rotation of video acquired, for example, by: 
    // AVAssetTrack *videoTrack = [tracks objectAtIndex:0]; 
    // CGAffineTransform preferredTransform = [videoTrack preferredTransform]; 
    // self.glKitView.preferredRotation = -1 * atan2(preferredTransform.b, preferredTransform.a); 

    // Preferred rotation for both portrait and landscape   
    mat4 rotationMatrix = mat4(cos(preferredRotation), -sin(preferredRotation), 0.0, 0.0, 
           sin(preferredRotation), cos(preferredRotation), 0.0, 0.0, 
           0.0,      0.0,     1.0, 0.0, 
           0.0,      0.0,     0.0, 1.0); 

    // Mirror vertical (portrait only) 
    mat4 rotationMatrix = mat4(cos(preferredRotation), sin(preferredRotation), 0.0, 0.0, 
           -sin(preferredRotation), cos(preferredRotation), 0.0, 0.0, 
           0.0,   0.0,   1.0, 0.0, 
           0.0,   0.0,   0.0, 1.0); 

    // Mirror horizontal (landscape only) 
    mat4 rotationMatrix = mat4(1.0, 0.0,      0.0,     0.0, 
           0.0, cos(preferredRotation), -sin(preferredRotation), 0.0, 
           0.0, sin(preferredRotation), cos(preferredRotation), 0.0, 
           0.0, 0.0,      0.0,     1.0); 

    // Mirror vertical (landscape only) 
    mat4 rotationMatrix = mat4(cos(preferredRotation), 0.0, sin(preferredRotation), 0.0, 
           0.0,     1.0, 0.0,     0.0, 
           -sin(preferredRotation), 0.0, cos(preferredRotation), 0.0, 
           0.0,     0.0, 0.0,     1.0); 

    gl_Position = position * rotationMatrix; 
    coordinate = texturecoordinate.xy; 
} 

Z każdym Vsync, można przekazać nową wartość dla preferredRotation, która będzie obracać widok bez rozciągania.

Oczywiście wybiera się tylko jedną matrycę4, w zależności od orientacji wideo, a następnie jej obrotu. Każdy matrix4 odwraca okno wideo - nie obraca go. Aby obrócić, musisz najpierw wybrać matrycę4 w oparciu o orientację, a następnie podstawić zmienną preferredRotation liczbą stopni (w radianach, formuła, dla której również podano).

Istnieje wiele sposobów obracania widoku, warstwy, obiektu itp .; ale jeśli renderujesz obraz przez OpenGL, powinieneś wybrać tę metodę i tylko tę metodę.

Powiązane problemy