본문 바로가기

카테고리 없음

안드로이드 OpenGL ES 예제, Cube 터치 이벤트

육면체의 모든 면에 텍스쳐를 적용하고 이용자의 터치 이벤트에 따라 큐브가 좌우로 회전하는 예

사용된 텍스쳐 이미지 및 실행된 결과 화면

TexturedCubeActivity 

package gl.test3;

import android.app.Activity;

import android.opengl.GLSurfaceView;

import android.os.Bundle;

import android.view.Window;

import android.view.WindowManager;


public class TexturedCubeActivity extends Activity {


@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);


// Remove the title bar from the window.

this.requestWindowFeature(Window.FEATURE_NO_TITLE);


// Make the windows into full screen mode.

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,

WindowManager.LayoutParams.FLAG_FULLSCREEN);


// Create a OpenGL view.

TouchGLSurfaceView view = new TouchGLSurfaceView(this);


// Creating and attaching the renderer.

TexturedCubeRenderer renderer = new TexturedCubeRenderer(this);

view.setRenderer(renderer);

setContentView(view);

}

}


TouchGLSurfaceView 

package gl.test3;


import android.content.Context;

import android.opengl.GLSurfaceView;

import android.util.Log;

import android.view.MotionEvent;


public class TouchGLSurfaceView extends GLSurfaceView {


private TexturedCubeRenderer renderer;

public TouchGLSurfaceView(Context context) {

super(context);

}

float prevX, prevY, curX, curY;

float angleY, angleX;

@Override

public boolean onTouchEvent(MotionEvent event) {

//Log.i("터치 이벤트", "터치 이벤트발생");

int action = event.getAction();

if(action==MotionEvent.ACTION_UP) {

//prevX=prevY=curX=curY=angleX=angleY=0;

prevX=prevY = 0;

}else if(action==MotionEvent.ACTION_MOVE) {

//Log.i("터치 이벤트", "Move 이벤트발생");

if(prevX==0 && prevY==0) {

prevX = event.getX();

prevY = event.getY();

return true;

}

curX = event.getX();

curY = event.getY();

if(curX - prevX > 0) {

this.renderer.angleY=(angleY+=5);

}else if(curX - prevX < 0) {

this.renderer.angleY=(angleY-=5);

}/*

if(curY - prevY >0) {

this.renderer.angleX=(angleX+=2);

}else if(curY - prevY <0) {// 위로

this.renderer.angleX=(angleX-=2);

}*/

}

return true;

}

@Override

public void setRenderer(Renderer renderer) {

super.setRenderer(renderer);

this.renderer = (TexturedCubeRenderer)renderer;

}

}


TexturedCubeRenderer 

package gl.test3;

import javax.microedition.khronos.egl.EGLConfig;

import javax.microedition.khronos.opengles.GL10;

import android.content.*;

import android.graphics.*;

import android.opengl.GLSurfaceView.Renderer;

import android.opengl.GLU;


public class TexturedCubeRenderer implements Renderer {

private Context context;

private MultiTexturedCube cube;

public TexturedCubeRenderer(Context context) {

this.context = context;

Bitmap []bitmap = new Bitmap[6];

bitmap[0] = BitmapFactory.decodeResource(context.getResources(), R.drawable.m1);

bitmap[1] = BitmapFactory.decodeResource(context.getResources(), R.drawable.m2);

bitmap[2] = BitmapFactory.decodeResource(context.getResources(), R.drawable.m3);

bitmap[3] = BitmapFactory.decodeResource(context.getResources(), R.drawable.m4);

bitmap[4] = BitmapFactory.decodeResource(context.getResources(), R.drawable.m5);

bitmap[5] = BitmapFactory.decodeResource(context.getResources(), R.drawable.m6);

cube = new MultiTexturedCube(bitmap);

}


public void onSurfaceCreated(GL10 gl, EGLConfig config) {

// Set the background color to black ( rgba ).

gl.glClearColor(1.0f, 1.0f, 1.0f, 0.5f);

// Enable Smooth Shading, default not really needed.

gl.glShadeModel(GL10.GL_SMOOTH);

// Depth buffer setup.

gl.glClearDepthf(1.0f);

// Enables depth testing.

gl.glEnable(GL10.GL_DEPTH_TEST);

// The type of depth testing to do.

gl.glDepthFunc(GL10.GL_LEQUAL);

// Really nice perspective calculations.

gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);

}


float angleX, angleY;

public void onDrawFrame(GL10 gl) {

// Clears the screen and depth buffer.

gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

// Replace the current matrix with the identity matrix

gl.glLoadIdentity();

// Translates 4 units into the screen.

gl.glTranslatef(0, 0, -10);

gl.glRotatef(20, 1, 0, 0); // 카메라를 향해 약간 기울여서 윗면이 보이도록 한다

gl.glRotatef(angleX, 1, 0, 0);

gl.glRotatef(angleY, 0, 1, 0);

// Draw our scene.

cube.draw(gl);

//angle += 5;

}


public void onSurfaceChanged(GL10 gl, int width, int height) {

// Sets the current view port to the new size.

gl.glViewport(0, 0, width, height);

// Select the projection matrix

gl.glMatrixMode(GL10.GL_PROJECTION);

// Reset the projection matrix

gl.glLoadIdentity();

// Calculate the aspect ratio of the window

GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f, 1000.0f);

// Select the modelview matrix

gl.glMatrixMode(GL10.GL_MODELVIEW);

// Reset the modelview matrix

gl.glLoadIdentity();

}


MultiTexturedCube

package gl.test3;


import java.nio.ByteBuffer;

import java.nio.ByteOrder;

import java.nio.FloatBuffer;

import java.nio.ShortBuffer;

import javax.microedition.khronos.opengles.GL10;

import android.graphics.Bitmap;

import android.opengl.GLUtils;


public class MultiTexturedCube {


// 육면체를 구성하는 6개의 면을 정점(24개)으로 표현한다

float [] vertices = {

    // 앞면

            -1.0f, -1.0f, 1.0f, // 왼쪽 아래 정점

            1.0f, -1.0f, 1.0f,  // 오른쪽 아래

            -1.0f, 1.0f, 1.0f,  // 왼쪽 위

            1.0f, 1.0f, 1.0f,   // 오른쪽 위

            // 오른쪽 면

            1.0f, -1.0f, 1.0f,  // 왼쪽 아래

            1.0f, -1.0f, -1.0f, // 오른쪽 아래         

            1.0f, 1.0f, 1.0f,   // 왼쪽 위

            1.0f, 1.0f, -1.0f,  // 오른쪽 위

            // 뒷면

            1.0f, -1.0f, -1.0f,

            -1.0f, -1.0f, -1.0f,            

            1.0f, 1.0f, -1.0f,

            -1.0f, 1.0f, -1.0f,

            // 왼쪽면

            -1.0f, -1.0f, -1.0f,

            -1.0f, -1.0f, 1.0f,         

            -1.0f, 1.0f, -1.0f,

            -1.0f, 1.0f, 1.0f,

            // 아래쪽 면

            -1.0f, -1.0f, -1.0f,

            1.0f, -1.0f, -1.0f,         

            -1.0f, -1.0f, 1.0f,

            1.0f, -1.0f, 1.0f,

            // 위쪽면

            -1.0f, 1.0f, 1.0f,

            1.0f, 1.0f, 1.0f,           

            -1.0f, 1.0f, -1.0f,

            1.0f, 1.0f, -1.0f,

};

// 36개의 정점을 이용하여 12개의 3각형을 구성한다

short [] indices = {

  //정점배열의 정점 인덱스를 이용하여 각 면마다 2개의 3각형(CCW)을 구성한다

            0,1,3, 0,3,2,           //앞면을 구성하는 2개의 3각형

            4,5,7, 4,7,6,           //오른쪽면 

            8,9,11, 8,11,10,        //... 

            12,13,15, 12,15,14,     

            16,17,19, 16,19,18,     

            20,21,23, 20,23,22,

};


// 정점배열에 선언된 정점의 위치에 텍스쳐 좌표를 배정한다. 해당 정점의 위치에 매핑할 텍스쳐 좌료를 선언하면 된다.

    // 인덱스 배열은 참고할 필요가 없고 정점배열의 정점 순서에 따라서 텍스쳐의 위치를 결정하는 것이 관건이다.

private float [] textures = {

//6개의 면에 매핑될 텍스쳐 좌표 24개를  선언한다

   0.0f, 1.0f,

            1.0f, 1.0f,

            0.0f, 0.0f,

            1.0f, 0.0f,

            

            0.0f, 1.0f,

            1.0f, 1.0f,

            0.0f, 0.0f,

            1.0f, 0.0f,

            

            0.0f, 1.0f,

            1.0f, 1.0f,

            0.0f, 0.0f,

            1.0f, 0.0f,

            

            0.0f, 1.0f,

            1.0f, 1.0f,

            0.0f, 0.0f,

            1.0f, 0.0f,

            

            0.0f, 1.0f,

            1.0f, 1.0f,

            0.0f, 0.0f,

            1.0f, 0.0f,

            

            0.0f, 1.0f,

            1.0f, 1.0f,

            0.0f, 0.0f,

            1.0f, 0.0f,

};

// Our vertex buffer.

private FloatBuffer vertexBuffer;


// Our index buffer.

private ShortBuffer indexBuffer;

// Our UV texture buffer.

private FloatBuffer textureBuffer;


// 다수개의 텍스쳐가 필요하므로 텍스쳐 아이디를 저장할 배열이 필요함

private int [] textureIds;

// The bitmap we want to load as a texture.

private Bitmap [] bitmap;

public MultiTexturedCube(Bitmap[] bitmap) {

// a float is 4 bytes, therefore we multiply the number if 

// vertices with 4.

ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);

vbb.order(ByteOrder.nativeOrder());

vertexBuffer = vbb.asFloatBuffer();

vertexBuffer.put(vertices);

vertexBuffer.position(0);

// short is 2 bytes, therefore we multiply the number if 

// vertices with 2.

ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);

ibb.order(ByteOrder.nativeOrder());

indexBuffer = ibb.asShortBuffer();

indexBuffer.put(indices);

indexBuffer.position(0);

ByteBuffer tbb = ByteBuffer.allocateDirect(vertices.length * 4);

tbb.order(ByteOrder.nativeOrder());

textureBuffer = tbb.asFloatBuffer();

textureBuffer.put(textures);

textureBuffer.position(0);

this.bitmap = bitmap;

}

public void draw(GL10 gl) {

// Counter-clockwise winding.

gl.glFrontFace(GL10.GL_CCW);

// Enable face culling.

gl.glEnable(GL10.GL_CULL_FACE);

// What faces to remove with the face culling.

gl.glCullFace(GL10.GL_BACK);

// Enabled the vertices buffer for writing and to be used during 

// rendering.

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);

// Specifies the location and data format of an array of vertex

// coordinates to use when rendering.

gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);

// 텍스쳐 관련 내용

gl.glEnable(GL10.GL_TEXTURE_2D);

// Enable the texture state

gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);


if(textureIds==null) loadGLTexture(gl);

// Point to our buffers

gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);

/*

gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, 

GL10.GL_UNSIGNED_SHORT, indexBuffer);

*/

                // 6개의 면을 구분하여 여러번 그릴 때마다 텍스쳐가 그려진다

for(int i=0; i<6; ++i)

{

   gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIds[i]);   //use texture of ith face

   indexBuffer.position(6*i);                          //select ith face

   GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap[i], 0);

   

   //draw 2 triangles making up this face

   gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_SHORT, indexBuffer);

}

// Disable the vertices buffer.

gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);

gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

gl.glDisable(GL10.GL_TEXTURE_2D);

// Disable face culling.

gl.glDisable(GL10.GL_CULL_FACE);

}

private void loadGLTexture(GL10 gl) {

// Generate one texture pointer...

textureIds = new int[6];

gl.glGenTextures(6, textureIds, 0); // 텍스쳐 아이디 6개 생성, 배열에 저장함, offset 0

// Create Nearest Filtered Texture

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

}

}