OpenGL의 스프라이트 애니메이션


9

OpenGL ES에서 스프라이트 애니메이션을 구현하는 데 문제가 있습니다. 나는 그것을 봤는데 내가 얻는 유일한 것은 Canvas를 통해 구현되는 자습서입니다.

방법을 알고 있지만 구현하는 데 문제가 있습니다.

필요한 것 : 충돌 감지에 대한 스프라이트 애니메이션.

내가 한 일 : 충돌 감지 기능이 제대로 작동합니다.

추신 : 모든 것이 잘 작동하지만 OPENGL에서만 애니메이션을 구현하고 싶습니다. 내 경우에는 캔버스가 작동하지 않습니다.

------------------------ 편집하다-----------------------

이제 아래에 특정 좌표가있는 스프라이트 시트가 있지만 어디에서 (u, v) 좌표가 시작됩니까? (0,0) 또는 (0,5)에서 내 u, v 좌표를 고려해야하고 어떤 패턴으로 내 목록에 저장해야합니까? ----> 왼쪽에서 오른쪽으로--> 위에서 아래로

스프라이트 클래스에 2D 배열이 필요합니까? 더 나은 이해를위한 이미지입니다.

스프라이트 시트 N = 3,4,5,6 등의 NxN 스프라이트 시트가 있다고 가정합니다.

.

.

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
스프라이트 애니메이션과 충돌 감지는 서로 관련이 없습니다.
API-Beast

어떤 종류의 애니메이션을 원하십니까? 골격, 스프라이트 시트, 다른 것?
GameDev-er

@ GameDev-er 스프라이트 시트가 있습니다.
Siddharth-Verma

1
@ Mr.Beast 나는 그들이 서로 관련이 없다는 것을 알고 있습니다. 충돌 후 스프라이트 애니메이션을 달성하려는 목표입니다. 지금까지 충돌 감지를 수행 할 수 있습니다. 그러나 스프라이트 애니메이션에 관한 한 .. 나는 그것을 할 수 없습니다. 추신 : 저는 GL ES를 처음 접하는 초보자이며 여기에서도 그렇습니다.
Siddharth-Verma

@Sid 왜 x / y가 섞여 있습니까? :( X는 가로 축입니다. (내가 아니라는 것을 알고 있지만, 반대해서는 안되는 규칙입니다)
doppelgreener

답변:


6

이것은 내 안드로이드 응용 프로그램에서 사용하는 코드 스 니펫입니다.

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

여기서 트릭은 glMatrixMode와 glTranslatef를 사용하는 것입니다. 그러면 uv 공간을 번역 할 수 있습니다.

uv 좌표의 범위는 (0,0)에서 (1,1)입니다.

4 개의 프레임으로 된 제곱 텍스처가 있고 쿼드를 텍스처링한다고 가정 해 봅시다. 나는 다음 좌표를 사용하여 uv 공간에서 프레임을 정의합니다 (선택은 당신에게 달려 있습니다)

첫 번째 (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)

glTexCoordPointer를 사용하면 쿼드에서 첫 번째 프레임을 매핑 한 다음 두 번째 프레임을 표시하려면 세 번째 및 glTranslatef (0.5, 0.5, 0에 대해 glTranslatef (0.5, 0, 0), glTranslatef (0, 0.5, 0)를 호출해야합니다 )에 해당합니다.

위의 코드는 테스트되어 잘 작동하므로 예제가 충분히 명확하기를 바랍니다.


편집하다:

그리기 기능이 끝나면이 코드로 텍스처 매트릭스를 재설정해야합니다.

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

예를 들어 5 행 4 열을 예로 들어 보겠습니다. 스프라이트 세트에 최대 20 개의 스프라이트가 있으므로 int idx = (int) ((System.currentTimeMillis () % 200 * number_of_sprites)) / 200);

idx는 이제 0에서 number_of_sprites-1 (예를 들어 5 개의 행, 4 개의 열이지만 18 개의 스프라이트 만있는 경우 <20 일 수 있음)로 200ms마다 값을 변경합니다. 스프라이트가 왼쪽에서 오른쪽, 위에서 아래로 있다고 가정하면 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);

idx % c를 수행 할 때 열 인덱스를 찾으면 결과는 항상 0과 c-1 사이입니다.

idx % c는 정수이므로 0.0에서 1.0 사이의 값으로 스케일링해야 cf로 나눌 수 있습니다. cf는 float이므로 암시 적 캐스트가 있습니다.

idx / c는 동일하지만 행의 경우 idx와 c는 모두 정수이므로 결과는 여전히 정수이며 행 인덱스는 rf로 나뉘어 0.0에서 1.0 사이의 값을 얻습니다.


여기에 삼각형 스트립을 사용하고 있습니다. 이 경우에도 작동합니까?
Siddharth-Verma

한가지 더 .. 어떤 방식으로 좌표를 저장해야합니까? ----> 1D 배열 ----> 2D 배열? 1D이면 배열에서 모든 좌표를 고려해야합니까?
Siddharth-Verma

@Sid 예, 같은 것입니다. 올바른 uv 매핑 좌표를 사용해야합니다. 코드를 게시하는 데 도움이 더 필요한 경우보다 코드 스 니펫을 조정 해보십시오
Marco Martinelli

glTexCoordPointer 필요위한 @Sid UV 좌표를 1 차원 어레이에 저장한다
마르코 마티를

1
내가 모르는 첫 번째 문제의 경우 여기에서 잘 작동합니다. 두 번째 문제의 경우 idx를 중지하여 0으로 롤백해야 간단한 트릭이 있습니다. 그 int oldIdx;전에 public FragileSquare()draw 메소드에서 변수 를 선언 하십시오 : int idx = oldIdx==(numberSprites-1) ? (numberSprites-1) : (int)((System.currentTimeMillis()%(200*numberSprites))/200); oldIdx = idx; 우리가 OT로 가고 있다고 생각하는 것처럼, 원래 질문에 대한 답이 될 것입니다. 필요한 경우이 질문을 닫고 새 질문을 열어야합니다.
Marco Martinelli

1

내 제안 : 애니메이션의 모든 프레임을 나란히 포함하는 텍스처를 만듭니다. 표시하려는 프레임에 따라 텍스처 좌표를 변경하십시오.


그것의 절반이 완료되었습니다. 그러나이 부분을 어떻게 달성해야합니까? "표시하려는 프레임에 따라 텍스처 좌표를 변경하십시오." 추신 : 저는 OpenGL ES의 초보자입니다.
Siddharth-Verma

1

스프라이트 시트 라는 것을 사용해야 합니다.

여기에 이미지 설명을 입력하십시오

스프라이트 시트는 캐릭터가 취할 수있는 포즈를 보여주는 모든 "프레임"이있는 단일 이미지입니다. 스프라이트 시트의 "프레임"을 시간 (폭발 애니메이션의 경우) 또는 플레이어 입력 (예 : 왼쪽, 오른쪽 또는 총을 그리는 등)을 기준으로 표시 할 프레임을 선택합니다.

이와 같은 작업을 수행 하는 가장 쉬운 방법은 모든 관련 스프라이트의 크기 (동일 너비 및 높이)가 동일하므로 왼쪽에서 네 번째 스프라이트의 (u) 좌표를 얻는 것은 단지 (sprite_width*4.0 / sprite_sheet_width)입니다.

공간을 효율적으로 최적화하고 최적화하려는 경우 TexturePacker 와 같은 도구를 사용 하여 스프라이트를 단일 시트에 포장 할 수 있습니다 . TexturePacker는 또한로드 한 각 스프라이트의 xy 위치를 설명하는 json 또는 xml 데이터를 방출합니다.


스프라이트 시트가 이미 있습니다. 나는 좌표를 이동 시켜서 그 방법을 알고 있습니다. 그러나 내 주요 질문은 "이것을 달성하는 방법은 openGL ES입니까?"입니다. 이것에 대한 의사 코드 또는 Java 코드가 있습니까? 알고리즘이 저에게 효과적 일 수 있습니다.
Siddharth-Verma

2
Sprite수업을 작성하십시오 . 내부 Sprite클래스의 목록 공원 (U, V) 텍스처의 각 "아직"의 (U, V) 좌표를 설명 쌍. 시간을 추적하려면 2 개의 변수가 더 필요합니다. 하나는 "초당 프레임 수"(각 애니메이션 프레임에 소비하는 # 초)를 저장하고 다른 하나는 "시계"라는 애니메이션주기에 "현재 시간"을 저장합니다. 그리려면 현재 시간을 업데이트해야합니다. "프레임 당 초"를 초과하면 애니메이션의 다음 프레임으로 이동하여 애니메이션이 계속 진행됩니다.
bobobobo

자, (u, v) 쌍을 포함하는 목록은 2D 배열입니까?
Siddharth-Verma

편집 된 질문을 참조하십시오.
Siddharth-Verma

1

OpenGL과 함께 I_COLLIDE 를 사용할 수 있습니다 .

월드의 각 엔티티를 상자로 만든 다음 상자의 각 축이 다른 엔티티와 충돌하는지 확인하십시오.

충돌을 테스트하기 위해 대량의 엔티티를 사용하면 octree에 체크인 할 수 있습니다. 간단히 세계를 섹터로 나누고 동일한 섹터에있는 객체 간의 충돌 만 확인하면됩니다.

또한 오픈 소스 충돌 감지 및 물리 엔진 인 Bullet 다이나믹 엔진을 활용하십시오.


충돌 감지가 이미 이루어졌습니다. 내 목표는 스프라이트 애니메이션을 만드는 것입니다.
Siddharth-Verma
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.