- rysować przeźroczyste bitmapy
- wykonywać przekształcenia modelowania
1. Przeźroczyste bitmapy.
Załóżmy, że posiadamy odpowiedni plik z obrazkiem posiadającym kanał alpha w formacie .png. Rysowanie i tworzenie bitmapy przebiega dokładnie tak samo jak w lekcji o rysowaniu oteksturowanych czworokątów. Musimy tylko uruchomić łączenie kolorów i określić sposób ich łączenia w buforze koloru przy pomocy funkcji glBlendFunc(). Jej pierwszy parametr określa funkcję łączenia źródła, drugi celu. W praktyce jest ich kilka, natomiast nie używa się ich prawie wcale. Do uzyskania przeźroczystości używamy takich konfiguracji.
gl.glEnable(GL10.GL_BLEND); // Włącz łączenie kolorów gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); // Określ funkcje łączenia kolorów
U mnie powyższy kod dawał efekt taki, że zamiast przeźroczystości widziałem w jej miejscu czarny kolor. Rozwiązaniem jest użycie innego parametru w funkcji glBlendFunc - mianowicie GL_ONE.
gl.glEnable(GL10.GL_BLEND); // Włącz łączenie kolorów gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA); // Określ funkcje łączenia kolorów;
Szczerze mówiąc nie chce mi się zagłębiać w specyfikację formatu PNG, wyczytałem na necie, że powyższe zmiany mają związek ze sposobem zapisu kanału alpha w pliku. Normalnie gdyby plik był zapisany zgodnie ze standardem, to pierwszy sposób z opcją GL_SRC_ALPHA powinien działać. Natomiast w życiu jak to w życiu, czasami ludzie mają standardy w ... gdzieś. Drugie ustawienia powinny załatwić sprawę.
2. Przekształcenia układu współrzędnych.
Okej, mamy już naszą kulkę na scenie. Teraz poznamy pokrótce przekształcenia układu współrzędnych: przesunięcie, obrót, skalowanie. Wprowadzą one trochę ruchu na naszą scenę.
glScalef(x, y, z) |
glTranslatef(x, y, z) |
glRotatef(angle, x, y, z) |
Obrót układu współrzędnych zapewnia nam funkcja glRotetef(angle, x, y, z), obrót dokonywany jest przeciwnie do ruchu wskazówek zegara (dla wartości dodatniej, jeśli podamy ujemną, to obracamy się zgodnie z ruchem wskazówek zegara). Kąt podajemy w stopniach.
Skalowanie finansuje funkcja glScalef(x, y, z). Odpowiednie wartości x, y, z jeśli są większe od 1 to powiększają tylokrotnie obiekt, natomiast jeśli są z zakresu od 0 do 1 to pomniejszają.
Te operacje przekształceń wykonywane są na aktualnej macierzy modelowania. Zauważmy, że jak np. przesuniemy układ współrzędnych, to tracimy informację o jego poprzednim położeniu. Ale możemy na to coś poradzić. Wykorzystamy dwie funkcje: glPushMatrix() oraz glPopMatrix() - glPushMatrix tworzy kopię aktualnej macierzy i odkłada ją na szczyt stosu macierzy. Dzięki temu po wykonaniu przekształceń możemy zdjąć (glPopMatrix) aktualną macierz ze stosu i powrócić do poprzedniego stanu.
Sprawdźmy to w praktyce.
Przypominam, że korzystam w dużej mierze z kodu lekcji 4, a więc środek naszego układu współrzędnych jest w lewym-dolnym rogu okna, my nie rysujemy naszego obiektu w środku układu współrzędnych, dlatego zmodyfikujemy odpowiednie wartości. Środek układu współrzędnych zostawimy w lewym-dolnym rogu okna, natomiast zrobimy tak, żeby rysowanie odbywało się w środku układu współrzędnych. Musimy zmienić współrzędne czworokąta tak, aby rysowany był wokół punktu (0.0, 0.0):
float quadsCoords[] = { // Pierwszy - 75.0f, - 75.0f, 0, 75.0f, - 75.0f, 0, 75.0f, 75.0f, 0, - 75.0f, 75.0f, 0, };W metodzie onDrawFrame organizujemy rysowanie tak:
public void onDrawFrame(GL10 gl) { // Wyczyść bufor głębi i koloru ustawioną wcześniej wartością GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT | GLES10.GL_DEPTH_BUFFER_BIT); // Ustaw kolor obiektu gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); if(angle < 360.0f) angle += 0.5f; else angle = angle - 360.0f; gl.glPushMatrix(); // Przesun układ z lewego-dolnego rogu na środek okna. gl.glTranslatef((float)resolutionX/2.0f, (float)resolutionY/2.0f, 0.0f); gl.glRotatef(angle, 0.0f, 0.0f, 1.0f); // Obróć gl.glTranslatef(0.0f, 50.0f, 0.0f); // Oddal od środka obrotu // Rysuj obiekt gl.glVertexPointer(3, GL10.GL_FLOAT, 0, quadsVB); gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, quadsTCB); gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_SHORT, quadsIB); gl.glPopMatrix(); }Powyższy przykład w łatwy sposób obrazuje zasadę działania omawianych przekształceń. Najpierw wyliczamy wartość kąta o jaki chcemy obrócić obiekt, bo przecież poprzez wywołania glPushMatrix i glPopMatrix po narysowaniu jednej klatki animacji przywracamy pierwotny układ współrzędnych sprzed obrotów. Przesuwamy układ na środek ekranu, obracamy go, przesuwamy wzdłuż osi y o 50 jednostek, rysujemy obiekt. Coś w powyższym kodzie jest nie do końca tak jak być powinno... widzisz to? Właśnie, modyfikacja kąta obrotu jest naiwna. Chodzi o to, że różnych urządzeniach będziemy mieli różne prędkości animacji. Zauważ, że w każdej klatce dodajemy pół stopnia, jeśli rysujemy 30 klatek na sekundę, to w ciągu tej sekundy uzyskamy 15 stopniowy obrót, natomiast na lepszym sprzęcie, gdzie wyciągniemy 120 klatek na sekundę w ciągu sekundy obrócimy się o 60 stopni. Rozwiązaniem jest uzależnienie zmian od czasu, zgodnie z tym, czego uczono nas w podstawówce: s = v * t ;). Dodajemy koło zmiennej angle odpowiednio:
private float angle = 0.0f; // kąt obrotu private long startTime = SystemClock.uptimeMillis(); // czas rozpoczęcia klatki private long deltaTime = 0L; // czas trwania klatkiNastępnie modyfikujemy metodę onDrawFrame:
public void onDrawFrame(GL10 gl) { // Mierz czas klatki deltaTime = SystemClock.uptimeMillis() - startTime; startTime = SystemClock.uptimeMillis(); // (...) angle += 0.2f * deltaTime; // (...) }Metoda SystemClock.uptimeMillis() zwraca czas, który upłynął od uruchomienia, nie licząc uśpienia. Na zakończenie wrzucam zrzut z telefonu, oczywiście ta kuleczka się porusza.
<< Poprzednia lekcja | Następna lekcja >> |
Materiały do pobrania: |
Brak komentarzy:
Prześlij komentarz