Sprite-Animation in openGL

9

Ich habe Probleme bei der Implementierung von Sprite-Animationen in openGL ES. Ich habe es gegoogelt und das einzige, was ich bekomme, ist das Tutorial, das über Canvas implementiert wird.

Ich kenne den Weg, habe aber Probleme bei der Umsetzung.

Was ich brauche: Eine Sprite-Animation zur Kollisionserkennung.

Was ich getan habe: Die Kollisionserkennungsfunktion funktioniert ordnungsgemäß.

PS: Alles funktioniert gut, aber ich möchte die Animation NUR in OPENGL implementieren. Leinwand funktioniert in meinem Fall nicht.

------------------------ BEARBEITEN -----------------------

Ich habe jetzt ein Sprite-Blatt, sagen wir das unten stehende mit einigen bestimmten Koordinaten, aber wo beginnen die (u, v) -Koordinaten? Sollte ich meine u, v-Koordinaten von (0,0) oder von (0,5) berücksichtigen und in welchem ​​Muster sollte ich sie in meiner Liste speichern? ----> Von links nach rechts ODER ----> von oben nach unten

Muss ich ein 2D-Array in meiner Sprites-Klasse haben? Hier ist das Bild zum besseren Verständnis.

Sprite-Blatt Ich gehe davon aus, dass ich ein NxN-Sprite-Blatt habe, wobei N = 3,4,5,6, .... und so weiter.

.

.

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();
}

}}

Siddharth-Verma
quelle
1
Sprite-Animation und Kollisionserkennung haben nichts miteinander zu tun.
API-Beast
Welche Art von Animation möchten Sie? Skelett, Sprite Sheet, noch etwas?
GameDev-er
@ GameDev-er Ich habe ein Sprite Sheet.
Siddharth-Verma
1
@ Mr.Beast Ich weiß, dass sie nichts miteinander zu tun haben. Mein Ziel ist es, nach einer Kollision eine Sprite-Animation zu erreichen. Bis jetzt bin ich in der Lage, Kollisionserkennung zu erreichen. Aber was Sprite-Animation betrifft, kann ich das nicht. PS: Ich bin ein Neuling bei openGL ES und auch hier. Es tut mir leid für meine Kommentare, falls vorhanden.
Siddharth-Verma
@Sid Warum hast du x / y verwechselt? :( X ist die horizontale Achse. (Ich weiß, es ist nicht von Natur aus, aber es ist eine Konvention, gegen die man nicht
verstoßen

Antworten:

6

Dies ist ein Codefragment, das ich in meiner Android-Anwendung verwende.

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

Der Trick dabei ist, glMatrixMode gefolgt von glTranslatef zu verwenden. Auf diese Weise können Sie den UV-Bereich übersetzen.

UV-Koordinaten reichen von (0,0) bis (1,1)

Angenommen, Sie haben eine quadratische Textur mit 4 Frames und möchten ein Quad texturieren. Ich werde die folgenden Koordinaten verwenden, um Frames im UV-Raum zu definieren (die Wahl liegt bei Ihnen)

1. (0, 0) (0,5, 0,5)

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

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

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

Mit glTexCoordPointer sollten Sie den 1. Frame auf Ihrem Quad zuordnen. Wenn Sie dann den 2. Frame anzeigen möchten, rufen Sie glTranslatef (0,5, 0, 0), glTranslatef (0, 0,5, 0) für den 3. und glTranslatef (0,5, 0,5, 0) auf ) für den 4 ..

Der obige Code ist getestet und funktioniert sehr gut. Ich hoffe, das Beispiel ist klar genug.


BEARBEITEN:

Am Ende Ihrer Zeichenfunktion sollten Sie Ihre Texturmatrix mit diesem Code zurücksetzen.

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

ok, nehmen wir als Beispiel 5 Zeilen und 4 Spalten. Ihr Spriteset enthält maximal 20 Sprites. Verwenden Sie daher int idx = (int) ((System.currentTimeMillis ()% 200 * number_of_sprites)) / 200);

idx wechselt jetzt von 0 zu number_of_sprites-1 (kann <20 sein, wenn Sie beispielsweise 5 Zeilen, 4 Spalten, aber nur 18 Sprites haben) und ändert seinen Wert alle 200 ms. Angenommen, Sie haben Ihr Sprite von links nach rechts und von oben nach unten, als Sie Ihre Rahmenkoordinate dabei im UV-Raum finden können.

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);

Wenn Sie idx% c ausführen, finden Sie Ihren Spaltenindex. Die Ergebnisse liegen immer zwischen 0 und c-1

idx% c ist eine Ganzzahl. Sie müssen sie auf einen Wert zwischen 0,0 und 1,0 skalieren, damit Sie durch cf dividieren können. cf ist ein Gleitkommawert, daher gibt es hier eine implizite Umwandlung

idx / c ist dasselbe, aber für Zeilen sind idx und c beide Ganzzahlen, sodass das Ergebnis immer noch Ganzzahlen ist, und es ist der Zeilenindex, dividiert durch rf, erhalten Sie einen Wert zwischen 0,0 und 1,0

Marco Martinelli
quelle
Ich benutze hier einen Dreiecksstreifen. Also wird es in diesem Fall funktionieren?
Siddharth-Verma
Noch etwas ... auf welche Weise soll ich die Koordinaten speichern? ----> 1D Array ----> 2D Array? Wenn 1D, welche Koordinaten sollte ich dann im Array berücksichtigen?
Siddharth-Verma
@Sid Ja, es ist das gleiche, Sie müssen nur die richtigen UV-Mapping-Koordinaten verwenden. Versuchen Sie, mein Code-Snippet anzupassen, als wenn Sie mehr Hilfe benötigen, um Ihren Code zu veröffentlichen
Marco Martinelli
@ Sid UV-Koordinaten für glTexCoordPointer müssen in 1D-Array gespeichert werden
Marco Martinelli
1
Für das erste Problem, das ich nicht kenne, funktioniert es hier einwandfrei. Für das zweite Problem müssen Sie idx stoppen, um auf 0 zurückzusetzen. Ein einfacher Trick ist dies also. Deklarieren Sie int oldIdx;vorher eine Variable public FragileSquare()in der Zeichenmethode. int idx = oldIdx==(numberSprites-1) ? (numberSprites-1) : (int)((System.currentTimeMillis()%(200*numberSprites))/200); oldIdx = idx; Gehen Sie folgendermaßen vor : Übrigens, ich denke, wir gehen OT, die ursprüngliche Frage wurde beantwortet. Vielleicht sollten Sie diese schließen und bei Bedarf eine neue öffnen.
Marco Martinelli
1

Mein Vorschlag: Erstellen Sie eine Textur, die alle Ihre Frames Ihrer Animation enthält (nebeneinander). Ändern Sie die Texturkoordinaten entsprechend dem Rahmen, den Sie anzeigen möchten.

Dolch
quelle
Die Hälfte davon ist erledigt. Aber wie soll ich diesen Teil erreichen? "Ändern Sie die Texturkoordinaten entsprechend dem Rahmen, den Sie anzeigen möchten." PS: Ich bin ein Neuling bei openGL ES.
Siddharth-Verma
1

Sie müssen ein sogenanntes Spritesheet verwenden .

Geben Sie hier die Bildbeschreibung ein

Ein Spritesheet ist nur ein einzelnes Bild mit all den verschiedenen "Frames", die die Posen zeigen, die der Charakter einnehmen kann. Sie wählen den "Frame" des Sprite-Blattes aus, der entweder basierend auf der Zeit (wie bei einer Explosionsanimation) oder auf der Eingabe durch den Spieler (z. B. nach links, rechts oder beim Zeichnen einer Waffe) angezeigt werden soll.

Der einfachste Weg, so etwas zu tun, besteht darin, dass alle zugehörigen Sprites dieselbe Größe (gleiche Breite und Höhe) haben. Daher ist es einfach, die (u) -Koordinate des 4. Sprites von links zu erhalten (sprite_width*4.0 / sprite_sheet_width).

Wenn Sie versuchen, zu optimieren und platzsparend zu sein, können Sie ein Tool wie TexturePacker verwenden, um Ihre Sprites auf ein einzelnes Blatt zu packen. TexturePacker gibt auch JSON- oder XML-Daten aus, die die xy-Positionen der einzelnen Sprites beschreiben, in die Sie laden.

Bobobobo
quelle
Ich habe bereits ein Sprite Sheet. Ich kenne die Methode, indem ich die Koordinaten verschiebe. Meine Hauptfrage lautet jedoch: "Wie kann dies erreicht werden, ist openGL ES?" Haben Sie einen Pseudocode oder einen Java-Code dafür? Der Algorithmus könnte für mich funktionieren.
Siddharth-Verma
2
Schreibe eine SpriteKlasse. Innerhalb des SpriteKlassenparks eine Liste von (u, v) Paaren, die die (u, v) Koordinaten jedes "Still" in der Textur beschreiben. Sie benötigen zwei weitere Variablen, um die Zeit zu verfolgen: einen Float zum Speichern von "Sekunden pro Frame" (# Sekunden für jeden Animationsframe) und einen weiteren Float namens "Clock", der die "aktuelle Zeit" im Animationszyklus speichert. Wenn Sie zum Zeichnen gehen, müssen Sie die aktuelle Zeit aktualisieren. Wenn "Sekunden pro Bild" überschritten wird, wechseln Sie zum nächsten Bild der Animation, sodass die Animation fortgesetzt wird.
Bobobobo
Okay, die Liste mit (u, v) Paaren ist also ein 2D-Array?
Siddharth-Verma
siehe die bearbeitete Frage bitte.
Siddharth-Verma
1

Sie können I_COLLIDE mit OpenGL verwenden.

Machen Sie jede Entität auf der Welt zu einer Box und prüfen Sie, ob jede der Achsen der Box mit anderen Entitäten kollidiert.

Bei einer großen Anzahl von Entitäten, die auf Kollisionen getestet werden sollen, möchten Sie möglicherweise in einen Octree einchecken. Sie würden die Welt einfach in Sektoren unterteilen und dann nur auf Kollisionen zwischen Objekten in denselben Sektoren prüfen.

Verwenden Sie auch die Bullet Dynamics Engine, eine Open-Source-Engine für Kollisionserkennung und Physik.

Md Mahbubur Rahman
quelle
Kollisionserkennung wurde bereits erreicht. Mein Ziel ist es, eine Sprite-Animation zu erstellen.
Siddharth-Verma