animación de sprites en openGL

9

Tengo problemas para implementar la animación de sprites en openGL ES. Lo busqué en Google y lo único que obtengo es el Tutorial que se implementa a través de Canvas.

Conozco el camino pero tengo problemas para implementarlo.

Lo que necesito: una animación de sprites sobre detección de colisiones.

Lo que hice: la función de detección de colisión funciona correctamente.

PD: Todo funciona bien, pero quiero implementar la animación SOLO en OPENGL. El lienzo no funcionará en mi caso.

------------------------ EDITAR -----------------------

Ahora tengo una hoja de sprites, digamos que la siguiente tiene algunas coordenadas determinadas, pero ¿desde dónde comenzarán las coordenadas (u, v)? ¿Debo considerar mis coordenadas u, v desde (0,0) o desde (0,5) y en qué patrón debo almacenarlas en mi lista ...? ----> De izquierda a derecha O ----> de arriba a abajo

¿Necesito tener una matriz 2D en mi clase de sprites? Aquí está la imagen para una mejor comprensión.

hoja de sprites Supongo que tengo una hoja de sprites NxN, donde N = 3,4,5,6, ... y así sucesivamente.

.

.

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
fuente
1
La animación de sprites y la detección de colisiones no tienen nada que ver entre sí.
API-Beast
¿Qué tipo de animación quieres? Esqueleto, hoja de sprite, ¿algo más?
GameDev-er
@ GameDev-er Tengo una hoja de sprites.
Siddharth-Verma
1
@ Mr.Beast Sé que no tienen nada que ver el uno con el otro. Mi objetivo es lograr la animación de sprites después de la colisión. Hasta ahora puedo lograr la detección de colisión. Pero en lo que respecta a la animación de sprites ... no puedo hacerlo. PD: soy un novato en OpenGL ES y aquí también ... lo siento por cualquiera de mis comentarios, si los hay.
Siddharth-Verma
@Sid ¿Por qué tienes x / y mezclado? :( X es el eje horizontal. (Sé que no es inherentemente, pero es una convención a la que no se debe ir en contra)
doppelgreener

Respuestas:

6

Este es un fragmento de código que estoy usando en mi aplicación de Android.

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

El truco aquí es usar glMatrixMode seguido de glTranslatef. Eso te permitirá traducir el espacio ultravioleta.

el rango de coordenadas uv varía de (0,0) a (1,1)

Supongamos que tiene una textura cuadrada con 4 cuadros y desea texturizar un quad. Usaré las siguientes coordenadas para definir marcos en el espacio uv (la elección depende de usted)

1er (0, 0) (0.5, 0.5)

2do (0.5, 0) (1, 0.5)

3er (0, 0.5) (0.5, 1)

4to (0.5, 0.5) (1, 1)

Con glTexCoordPointer debe asignar el primer fotograma en su quad y luego, cuando desee mostrar el segundo fotograma, llame a glTranslatef (0.5, 0, 0), glTranslatef (0, 0.5, 0) para el tercero y glTranslatef (0.5, 0.5, 0 ) para el 4to.

El código anterior está probado y funciona muy bien, espero que el ejemplo sea lo suficientemente claro.


EDITAR:

Al final de su función de dibujo, debe restablecer su matriz de textura con este código.

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

ok, tomemos 5 filas y 4 columnas como ejemplo. Hay un máximo de 20 sprites en su conjunto de sprites, así que use int idx = (int) ((System.currentTimeMillis ()% 200 * number_of_sprites))) / 200);

idx ahora va de 0 a number_of_sprites-1 (puede ser <20 si tiene, por ejemplo, 5 filas, 4 columnas pero solo 18 sprites) cambiando su valor cada 200 ms. Suponiendo que tiene su sprite de izquierda a derecha y de arriba a abajo, puede encontrar su coordenada de marco en el espacio uv haciendo esto.

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

cuando haces idx% c encuentras el índice de tu columna, los resultados siempre están entre 0 y c-1

idx% c es un número entero, necesita escalarlo a un valor entre 0.0 y 1.0 para dividirlo por cf, cf es un flotante, por lo que aquí hay una conversión implícita

idx / c es lo mismo pero para las filas, idx y c son ambos enteros, por lo que el resultado sigue siendo entero, y es el índice de la fila, dividiendo entre rf obtienes un valor entre 0.0 y 1.0

Marco Martinelli
fuente
Estoy usando una tira triangular aquí. Entonces, ¿funcionará en este caso?
Siddharth-Verma
Una cosa más ... ¿de qué manera debo almacenar las coordenadas? ----> matriz 1D ----> matriz 2D? Si es 1D, entonces, ¿qué todas las coordenadas debería considerar en la matriz?
Siddharth-Verma
@Sid Sí, es lo mismo, solo necesita usar las coordenadas de mapeo uv correctas. Intente adaptar mi fragmento de código que si necesita más ayuda para publicar su código
Marco Martinelli
Las coordenadas UV @Sid para glTexCoordPointer deben almacenarse en una matriz 1D
Marco Martinelli el
1
para el primer problema, no sé, está funcionando bien aquí, para el segundo, debe detener idx para volver a 0, así que un simple truco es este. Declare una variable int oldIdx;antes de public FragileSquare()eso en el método de dibujo, haga esto: int idx = oldIdx==(numberSprites-1) ? (numberSprites-1) : (int)((System.currentTimeMillis()%(200*numberSprites))/200); oldIdx = idx; Por cierto, creo que vamos a OT, la pregunta original fue respondida, tal vez debería cerrar esta y abrir una nueva si es necesario.
Marco Martinelli
1

Mi sugerencia: cree una textura que contenga todos los cuadros de su animación (uno al lado del otro). Cambie las coordenadas de textura de acuerdo con el marco que desea mostrar.

Puñal
fuente
La mitad se ha hecho. Pero, ¿cómo debo lograr esta parte ...... "Cambiar las coordenadas de textura de acuerdo con el marco que desea mostrar". PD: soy un novato en openGL ES.
Siddharth-Verma
1

Necesitas usar algo llamado una hoja de sprites .

ingrese la descripción de la imagen aquí

Una hoja de sprites es solo una imagen con todos los diferentes "cuadros" que muestran las poses que el personaje puede tomar. Usted selecciona qué "marco" de la hoja de sprites para mostrar, ya sea en función del tiempo (como para una animación de explosión) o de la entrada del jugador (como mirar hacia la izquierda, derecha o dibujar un arma)

La forma más fácil de hacer algo como esto es hacer que todos los sprites relacionados tengan el mismo tamaño (mismo ancho y altura), y así obtener la coordenada (u) del 4to sprite desde la izquierda es justo (sprite_width*4.0 / sprite_sheet_width).

Si está tratando de optimizar y ahorrar espacio, puede usar una herramienta como TexturePacker para empacar sus sprites en una sola hoja. TexturePacker también emite datos json o xml que describen las ubicaciones xy de cada uno de los sprites en los que carga.

bobobobo
fuente
Ya tengo una hoja de sprites. Conozco el método, es cambiando las coordenadas. Pero mi pregunta principal es "¿Cómo lograr esto es openGL ES?" ¿tienes algún pseudocódigo o un código java para esto? El algoritmo podría funcionar para mí.
Siddharth-Verma
2
Escribe una Spriteclase. Dentro de la Spriteclase, estacione una lista de pares (u, v) que describen las coordenadas (u, v) de cada "imagen fija" en la textura. Necesita 2 variables más para rastrear el tiempo: un flotador para almacenar "segundos por cuadro" (# segundos para gastar en cada cuadro de animación) y otro flotante llamado "reloj", que almacena el "tiempo actual" en el ciclo de animación. Cuando vaya a dibujar, debe actualizar la hora actual. Cuando se exceden los "segundos por fotograma", pasa al siguiente fotograma de la animación, de modo que la animación continúa.
bobobobo
Bien, ¿entonces la lista que contiene pares (u, v) será una matriz 2d?
Siddharth-Verma
vea la pregunta editada por favor.
Siddharth-Verma
1

Puede usar I_COLLIDE con OpenGL.

Haga que cada entidad en el mundo sea una caja, luego verifique si cada uno de los ejes de la caja está colisionando con otras entidades.

Con grandes cantidades de entidades para detectar colisiones, es posible que desee registrarse en un octree. Simplemente dividiría el mundo en sectores, luego solo verificaría la colisión entre objetos en los mismos sectores.

También utilice el motor de dinámica Bullet, que es un motor de física y detección de colisiones de código abierto.

Md Mahbubur Rahman
fuente
La detección de colisión ya se ha logrado. Mi objetivo es crear una animación de sprites.
Siddharth-Verma