Saturday, January 18, 2020

android - sprite animation in openGL


I am facing problems on implementing sprite animation in openGL ES. I've googled it and the only thing i am getting is the Tutorial implementing via Canvas.


I know the way but I am having problems in implementing it.


What I need : A sprite animation on collision detection.



What I did : Collision Detection function working properly.


PS : Everything is working fine but i want to implement the animation in OPENGL ONLY. Canvas won't work in my case.


------------------------ EDIT-----------------------


I now have a sprite sheet, say the one below having some certain co-ordinates, but from where will be the (u,v) co-ordinates start? Should I consider my u,v co-ordinates from (0,0) or from (0,5) and in which pattern should i store them in my list..? ----> From Left to right OR ----> from top to bottom


Do i need to have a 2D array in my sprites class? here is the image for a better understanding.


Sprite sheet I am assuming that I have a NxN sprite sheet, where N = 3,4,5,6,....and so on.


.


.


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

}



Answer




This is a code snippet I'm using in my Android application.


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

The trick here is to use glMatrixMode followed by glTranslatef. That will allow you to translate the uv space.



uv coordinates range from (0,0) to (1,1)


Let's suppose you have a squared texture with 4 frames and you want to texturize a quad. I will use the following coordinates to define frames in uv space (the choice is up to you)


1st (0, 0) (0.5, 0.5)


2nd (0.5, 0) (1, 0.5)


3rd (0, 0.5) (0.5, 1)


4th (0.5, 0.5) (1, 1)


With glTexCoordPointer you should map the 1st frame on your quad then when you want to show the 2nd frame you call glTranslatef(0.5, 0, 0), glTranslatef(0, 0.5, 0) for the 3rd and glTranslatef(0.5, 0.5, 0) for the 4th.


The code above is tested and work very well, I hope the example is clear enough.




EDIT:



at the end of your draw function you should reset your texture matrix whit this code.


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



ok, let's take 5 rows and 4 columns as an example. There are max 20 sprites in your spriteset so use int idx = (int)((System.currentTimeMillis()%200*number_of_sprites)))/200);


idx now go from 0 to number_of_sprites-1 (can be < 20 if you have for example 5 rows, 4 columns but only 18 sprite) changing it's value every 200ms. Assuming you have your sprite from left to right and from top to bottom than you can find your frame coordinate in uv space doing this.


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

when you do idx%c you find your column index, the results is always between 0 and c-1


idx%c is an integer, you need to scale it to a value between 0.0 and 1.0 so you divide by cf, cf is a float so there is an implicit cast here


idx/c is the same thing but for rows, idx and c are both integer so the result is still integer, and it's the row index, dividing by rf you get a value between 0.0 and 1.0


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...