animacja ikonek w openGL


9

Mam problemy z implementacją animacji ikonek w OpenGL ES. Poszukałem go i jedyne, co otrzymuję, to samouczek wdrażający przez Canvas.

Znam sposób, ale mam problemy z jego wdrożeniem.

Czego potrzebuję: animacja duszka po wykryciu kolizji.

Co zrobiłem: funkcja wykrywania kolizji działa poprawnie.

PS: Wszystko działa dobrze, ale chcę zaimplementować animację TYLKO w OPENGL. Płótno nie działa w moim przypadku.

------------------------ EDYTOWAĆ-----------------------

Mam teraz arkusz duszka, powiedzmy, że poniżej ma pewne określone współrzędne, ale skąd zaczną się współrzędne (u, v)? Czy powinienem wziąć pod uwagę moje współrzędne u, v z (0,0) czy z (0,5) i w jakim wzorze powinienem je zapisać na mojej liście? ----> Od lewej do prawej LUB ----> od góry do dołu

Czy muszę mieć tablicę 2D w mojej klasie duszków? oto obraz dla lepszego zrozumienia.

Arkusz duszka Zakładam, że mam arkusz sprite NxN, gdzie N = 3,4,5,6, .... i tak dalej.

.

.

class FragileSquare{

FloatBuffer fVertexBuffer, mTextureBuffer;

ByteBuffer mColorBuff;

ByteBuffer mIndexBuff;

int[] textures = new int[1];

public boolean beingHitFromBall = false;

int numberSprites = 49;

int columnInt = 7;      //number of columns as int

float columnFloat = 7.0f; //number of columns as float

float rowFloat = 7.0f;


public FragileSquare() {
    // TODO Auto-generated constructor stub

    float vertices [] = {-1.0f,1.0f,            //byte index 0
                         1.0f, 1.0f,            //byte index 1
                                    //byte index 2
                         -1.0f, -1.0f,
                         1.0f,-1.0f};           //byte index 3


    float textureCoord[] = {
                            0.0f,0.0f,
                            0.142f,0.0f,
                            0.0f,0.142f,
                            0.142f,0.142f           


    };


    byte indices[] = {0, 1, 2,
            1, 2, 3 };

    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4*2 * 4); // 4 vertices, 2 co-ordinates(x,y) 4 for converting in float
    byteBuffer.order(ByteOrder.nativeOrder());
    fVertexBuffer = byteBuffer.asFloatBuffer();
    fVertexBuffer.put(vertices);
    fVertexBuffer.position(0);

    ByteBuffer byteBuffer2 = ByteBuffer.allocateDirect(textureCoord.length * 4);
    byteBuffer2.order(ByteOrder.nativeOrder());
    mTextureBuffer =  byteBuffer2.asFloatBuffer();
    mTextureBuffer.put(textureCoord);
    mTextureBuffer.position(0);

}



public void draw(GL10 gl){


    gl.glFrontFace(GL11.GL_CW);

    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glVertexPointer(1,GL10.GL_FLOAT, 0, fVertexBuffer);
    gl.glEnable(GL10.GL_TEXTURE_2D);
    int idx = (int) ((System.currentTimeMillis()%(200*4))/200);
    gl.glMatrixMode(GL10.GL_TEXTURE); 
    gl.glTranslatef((idx%columnInt)/columnFloat, (idx/columnInt)/rowFloat, 0);
    gl.glMatrixMode(GL10.GL_MODELVIEW); 
    gl.glEnable(GL10.GL_BLEND);
    gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); //4
    gl.glTexCoordPointer(2, GL10.GL_FLOAT,0, mTextureBuffer); //5
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); //7
    gl.glFrontFace(GL11.GL_CCW);
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    gl.glMatrixMode(GL10.GL_TEXTURE);
    gl.glLoadIdentity();
    gl.glMatrixMode(GL10.GL_MODELVIEW);
}

public void loadFragileTexture(GL10 gl, Context context, int resource)
{
    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resource);
    gl.glGenTextures(1, textures, 0);
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
    bitmap.recycle();
}

}


1
Animacja duszka i wykrywanie kolizji nie mają ze sobą nic wspólnego.
API-Beast,

Jakiego rodzaju animacji chcesz? Szkieletowy, arkusz sprite, coś jeszcze?
GameDev-er

@ GameDev-er Mam arkusz ikonek.
Siddharth-Verma,

1
@ Mr.Beast Wiem, że nie mają ze sobą nic wspólnego. Moim celem jest uzyskanie animacji duszka po zderzeniu. Do tej pory jestem w stanie osiągnąć wykrycie kolizji. Ale jeśli chodzi o animację duszków, nie jestem w stanie tego zrobić. PS: Jestem nowicjuszem w openGL ES i tutaj też .. przepraszam za jakiekolwiek moje komentarze, jeśli w ogóle.
Siddharth-Verma,

@Sid Dlaczego pomieszałeś x / y? :( X jest osią poziomą. (Wiem, że nie jest z natury związana, ale jest konwencją, której nie należy się sprzeciwiać)
doppelgreener

Odpowiedzi:


6

To jest fragment kodu, którego używam w mojej aplikacji na Androida.

gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glMatrixMode(GL10.GL_TEXTURE);    //edit the texture matrix
gl.glTranslatef(u, v, 0);            //translate the uv space (you can also rotate, scale, ...)
gl.glMatrixMode(GL10.GL_MODELVIEW);  //go back to the modelview matrix
gl.glBindTexture(GL10.GL_TEXTURE_2D, getTexture());
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);           //map the texture on the triangles
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, getTextureBuffer()); //load texture coordinates

Sztuką jest użycie glMatrixMode, a następnie glTranslatef. To pozwoli ci przetłumaczyć przestrzeń UV.

Współrzędne UV wahają się od (0,0) do (1,1)

Załóżmy, że masz kwadratową teksturę z 4 ramkami i chcesz teksturować quad. Użyję następujących współrzędnych do zdefiniowania ramek w przestrzeni UV (wybór należy do Ciebie)

1st (0, 0) (0,5, 0,5)

2. miejsce (0,5; 0) (1; 0,5)

3 (0, 0,5) (0,5, 1)

4. (0,5; 0,5) (1, 1)

Z glTexCoordPointer powinieneś zmapować pierwszą ramkę na quadzie, a następnie, aby wyświetlić drugą ramkę, wywołujesz glTranslatef (0,5, 0, 0), glTranslatef (0, 0,5, 0) dla 3. i glTranslatef (0,5, 0,5, 0 ) dla czwartego.

Powyższy kod został przetestowany i działa bardzo dobrze, mam nadzieję, że przykład jest wystarczająco jasny.


EDYTOWAĆ:

na końcu funkcji rysowania powinieneś zresetować matrycę tekstur za pomocą tego kodu.

gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glMatrixMode(GL10.GL_TEXTURE);
gl.glLoadIdentity();
gl.glMatrixMode(GL10.GL_MODELVIEW);

ok, weźmy jako przykład 5 wierszy i 4 kolumny. W twoim zestawie sprite jest maksymalnie 20, więc użyj int idx = (int) ((System.currentTimeMillis ()% 200 * liczba_sprites))) / 200);

idx teraz przechodzi od 0 do number_of_sprites-1 (może być <20, jeśli masz na przykład 5 wierszy, 4 kolumny, ale tylko 18 duszków) zmieniając jego wartość co 200 ms. Zakładając, że masz swojego duszka od lewej do prawej i od góry do dołu, niż możesz to zrobić współrzędną ramki w przestrzeni UV.

int c = 4;      //number of columns as int
float cf = 4.f; //number of columns as float
float rf = 5.f; //number of rows as float
gl.glTranslatef((idx%c)/cf, (idx/c)/rf, 0);

kiedy robisz idx% c, znajdujesz indeks kolumny, wyniki zawsze wynoszą od 0 do c-1

idx% c jest liczbą całkowitą, musisz przeskalować ją do wartości od 0,0 do 1,0, więc dzielimy przez cf, cf jest liczbą zmiennoprzecinkową, więc tutaj jest niejawna obsada

idx / c to to samo, ale dla wierszy oba idx i c są liczbami całkowitymi, więc wynik jest nadal liczbą całkowitą, a to indeks wiersza, dzieląc przez rf, otrzymujesz wartość od 0,0 do 1,0


Używam tutaj paska trójkąta. Czy to zadziała w tym przypadku?
Siddharth-Verma,

Jeszcze jedno ... w jaki sposób powinienem przechowywać współrzędne? ----> tablica 1D ----> tablica 2D? Jeśli 1D, to jakie wszystkie współrzędne powinienem wziąć pod uwagę w tablicy?
Siddharth-Verma,

@Sid Tak, to jest to samo, wystarczy użyć odpowiednich współrzędnych mapowania UV. Spróbuj dostosować mój fragment kodu, niż jeśli potrzebujesz pomocy w opublikowaniu kodu
Marco Martinelli,

@Sid Współrzędne UV dla glTexCoordPointer muszą być przechowywane w tablicy 1D
Marco Martinelli,

1
w przypadku pierwszego problemu nie wiem, tutaj działa dobrze, w drugim przypadku musisz zatrzymać idx, aby cofnąć się do zera, więc jest to prosta sztuczka. Zadeklaruj zmienną int oldIdx;wcześniej public FragileSquare()w metodzie rysowania: zrób tak: int idx = oldIdx==(numberSprites-1) ? (numberSprites-1) : (int)((System.currentTimeMillis()%(200*numberSprites))/200); oldIdx = idx; Przy okazji, myślę, że idziemy OT, pierwotne pytanie zostało udzielone, może powinieneś zamknąć tę i otworzyć nową, jeśli to konieczne.
Marco Martinelli,

1

Moja sugestia: utwórz teksturę zawierającą wszystkie klatki animacji (obok siebie). Zmień współrzędne tekstury zgodnie z ramką, którą chcesz wyświetlić.


Połowa z tego została zrobiona. Ale jak mam osiągnąć tę część ...... „Zmień współrzędne tekstury zgodnie z ramką, którą chcesz wyświetlić”. PS: Jestem nowicjuszem w openGL ES.
Siddharth-Verma,

1

Musisz użyć czegoś zwanego arkuszem sprite .

wprowadź opis zdjęcia tutaj

Arkusz sprite to tylko jedno zdjęcie ze wszystkimi różnymi „ramkami”, które pokazują pozy, jakie może przyjąć postać. Ty wybierasz „ramkę” arkusza sprite do wyświetlenia na podstawie czasu (jak w przypadku animacji eksplozji) lub na podstawie danych wejściowych gracza (takich jak skierowanie w lewo, w prawo lub wyciągnięcie broni)

Najprostszym sposobem, aby zrobić coś takiego jest, aby wszystkie powiązane skrzaty być tej samej wielkości (sama szerokość i wysokość), a więc uzyskiwanie (u) współrzędna 4 ikonki z lewej strony jest po prostu (sprite_width*4.0 / sprite_sheet_width).

Jeśli próbujesz zoptymalizować i uzyskać oszczędność miejsca, możesz użyć narzędzia takiego jak TexturePacker, aby spakować swoje duszki na jednym arkuszu. TexturePacker emituje również dane json lub xml, które opisują lokalizacje xy każdej z sprite'ów, do których ładujesz.


Mam już arkusz sprite. znam metodę, przesuwając współrzędne. Ale moje główne pytanie brzmi: „Jak to osiągnąć, jest openGL ES?” czy masz do tego jakiś pseudo-kod lub kod Java? Algorytm może dla mnie działać.
Siddharth-Verma,

2
Napisać Sprite klasę. Wewnątrz Spriteparku zapisz listę par (u, v), które opisują współrzędne (u, v) każdej „nieruchomej” tekstury. Potrzebujesz 2 dodatkowych zmiennych do śledzenia czasu: jeden zmiennoprzecinkowy do przechowywania „sekund na klatkę” (# sekund do wydania na każdą ramkę animacji), a drugi zmiennoprzecinkowy o nazwie „zegar”, który przechowuje „bieżący czas” w cyklu animacji. Kiedy idziesz do losowania, musisz zaktualizować aktualny czas. Po przekroczeniu „sekund na klatkę” przechodzisz do następnej klatki animacji, aby animacja była kontynuowana.
bobobobo

Ok, więc lista zawierająca pary (u, v) będzie tablicą 2d?
Siddharth-Verma,

zobacz edytowane pytanie.
Siddharth-Verma,

1

Możesz używać I_COLLIDE z OpenGL.

Ustaw każdą jednostkę na świecie w pole, a następnie sprawdź, czy każda z osi ramki koliduje z innymi jednostkami.

Przy dużej ilości jednostek do testowania kolizji możesz chcieć sprawdzić w oktawie. Wystarczy podzielić świat na sektory, a następnie sprawdzić tylko kolizję między obiektami w tych samych sektorach.

Wykorzystaj także silnik dynamiki Bullet, który jest mechanizmem wykrywania kolizji typu open source i silnikiem fizyki.


wykrywanie kolizji zostało już osiągnięte. Moim celem jest stworzenie animacji duszka.
Siddharth-Verma,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.