- 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