opengl es 로 간단하게 3d를 구현하려고 하는데요..

제가 하고자 하는 부분은 큐브 퍼즐처럼 조그만한 큐브9개가 큰 큐브하나를 구성하고 있는 모양입니다.

 

큐브의 가운데 중점을 기준으로 줌인/아웃, 및 xy축 회전을 하고 싶은데요..

현재 큐브 하나로 위의 기능을 구현했습니다..

 

하지만 여러개의 큐브로 커다란 큐브를 구성하는것에서 어려움이있네요..

(각각의 작은 큐브를 나중에 객체로 인식하여 터치나 클릭을 인식할수 있어야 합니다..)

 

제가 궁금한점은..

1. 여러개의 큐브를 가지고 커다란 하나의 큐브러처럼 구성하는법

2. 작은 큐브를 객체로 인식하여 터치 이벤트를 받는 법 입니다..

 

아래는 예제소스를 활용해서 제가 현재 구현한 텍스쳐를 입힌 큐브 하나짜리입니다..

조언 부탁드립니다..

 

myview

 public class myview extends GLSurfaceView implements Renderer{ /** Cube instance */
 private cube cube; 
 
 /* Rotation values */
 private float xrot;     //X Rotation
 private float yrot;     //Y Rotation
 private float z = -5.0f;   //Depth Into The Screen
 
 private int filter = 0;    //Which texture filter?
 
 /** Is light enabled */
 private boolean light = false;
 /** Is blending enabled ( NEW ) */
 private boolean blend = false;
 /* The initial light values */
 private float[] lightAmbient = {0.5f, 0.5f, 0.5f, 1.0f};
 private float[] lightDiffuse = {1.0f, 1.0f, 1.0f, 1.0f};
 private float[] lightPosition = {0.0f, 0.0f, 2.0f, 1.0f};
  
 /* The buffers for our light values */
 private FloatBuffer lightAmbientBuffer;
 private FloatBuffer lightDiffuseBuffer;
 private FloatBuffer lightPositionBuffer;
 
 /* Variables and factor for the input handler */
 private float oldX;
    private float oldY;
 private final float TOUCH_SCALE = 0.2f;   //Proved to be good for normal rotation
 
 /** The Activity Context */
 private Context context;
 
 /**
  * Instance the Cube object and set the Activity Context 
  * handed over. Initiate the light buffers and set this 
  * class as renderer for this now GLSurfaceView.
  * Request Focus and set if focusable in touch mode to
  * receive the Input from Screen and Buttons  
  * 
  * @param context - The Activity Context
  */
 public myview(Context context, AttributeSet attrs) {
  super(context, attrs);
  
  //Set this as Renderer
  this.setRenderer(this);
  //Request focus, otherwise buttons won't react
  this.requestFocus();
  this.setFocusableInTouchMode(true);
  
  //
  this.context = context;  
  
  //
  ByteBuffer byteBuf = ByteBuffer.allocateDirect(lightAmbient.length * 4);
  byteBuf.order(ByteOrder.nativeOrder());
  lightAmbientBuffer = byteBuf.asFloatBuffer();
  lightAmbientBuffer.put(lightAmbient);
  lightAmbientBuffer.position(0);
  
  byteBuf = ByteBuffer.allocateDirect(lightDiffuse.length * 4);
  byteBuf.order(ByteOrder.nativeOrder());
  lightDiffuseBuffer = byteBuf.asFloatBuffer();
  lightDiffuseBuffer.put(lightDiffuse);
  lightDiffuseBuffer.position(0);
  
  byteBuf = ByteBuffer.allocateDirect(lightPosition.length * 4);
  byteBuf.order(ByteOrder.nativeOrder());
  lightPositionBuffer = byteBuf.asFloatBuffer();
  lightPositionBuffer.put(lightPosition);
  lightPositionBuffer.position(0);
  
  //
  cube = new cube();
  
 }
 /**
  * 그리기 표면이 생성될때 호출
  * The Surface is created/init()
  */
 public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
  //And there'll be light!
  gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbientBuffer);  //Setup The Ambient Light
  gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuseBuffer);  //Setup The Diffuse Light
  gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPositionBuffer); //Position The Light
  gl.glEnable(GL10.GL_LIGHT0);           //Enable Light 0
  
  //Blending
  gl.glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
  gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);  //Set The Blending Function For Translucency ( NEW )
  //Settings
  gl.glDisable(GL10.GL_DITHER);    //Disable dithering
  gl.glEnable(GL10.GL_TEXTURE_2D);   //Enable Texture Mapping
  gl.glShadeModel(GL10.GL_SMOOTH);    //Enable Smooth Shading
  gl.glClearDepthf(1.0f);      //Depth Buffer Setup
  gl.glEnable(GL10.GL_DEPTH_TEST);    //Enables Depth Testing
  gl.glDepthFunc(GL10.GL_LEQUAL);    //The Type Of Depth Testing To Do
  
  //Really Nice Perspective Calculations
  gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST); 
    
  //Load the texture for the cube once during Surface creation
  cube.loadGLTexture(gl, this.context);
 }
 /**
  * 프레임을 그릴때마다 호출
  * Here we do our drawing
  */
 public void onDrawFrame(GL10 gl) {
  //Clear Screen And Depth Buffer
  gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 
  gl.glLoadIdentity();     //Reset The Current Modelview Matrix
  
  //Check if the light flag has been set to enable/disable lighting
  if(light) {
   gl.glEnable(GL10.GL_LIGHTING);
  } else {
   gl.glDisable(GL10.GL_LIGHTING);
  }
  
  //Check if the blend flag has been set to enable/disable blending
  if(blend) {
   gl.glEnable(GL10.GL_BLEND);   //Turn Blending On ( NEW )
   gl.glDisable(GL10.GL_DEPTH_TEST); //Turn Depth Testing Off ( NEW )
   
  } else {
   gl.glDisable(GL10.GL_BLEND);  //Turn Blending On ( NEW )
   gl.glEnable(GL10.GL_DEPTH_TEST); //Turn Depth Testing Off ( NEW )
  }
  
  //Drawing
  gl.glTranslatef(0.0f, 0.0f, z);   //Move z units into the screen
  gl.glScalef(0.8f, 0.8f, 0.8f);    //Scale the Cube to 80 percent, otherwise it would be too large for the screen
  
  //Rotate around the axis based on the rotation matrix (rotation, x, y, z)
  gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f); //X
  gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f); //Y
    
  cube.draw(gl, filter);     //Draw the Cube 
   }
  
 /**
  * 표면의 크기가 변경되거나, 최초에 호출
  * If the surface changes, reset the view
  */
 public void onSurfaceChanged(GL10 gl, int width, int height) {
  if(height == 0) {       //Prevent A Divide By Zero By
   height = 1;       //Making Height Equal One
  }
  gl.glViewport(0, 0, width, height);  //Reset The Current Viewport
  gl.glMatrixMode(GL10.GL_PROJECTION);  //Select The Projection Matrix
  gl.glLoadIdentity();      //Reset The Projection Matrix
  //Calculate The Aspect Ratio Of The Window
  GLU.gluPerspective(gl, 45.0f, (float)width / (float)height, 0.1f, 100.0f);
  gl.glMatrixMode(GL10.GL_MODELVIEW);  //Select The Modelview Matrix
  gl.glLoadIdentity();      //Reset The Modelview Matrix
 }
 
  
 /**
  * Override the touch screen listener.
  * React to moves and presses on the touchscreen.
  */
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  //
  float x = event.getX();
        float y = event.getY();
        
        if(event.getAction() == MotionEvent.ACTION_MOVE) {
         //Calculate the change
         float dx = x - oldX;
         float dy = y - oldY;
          
         xrot += dy * TOUCH_SCALE;
         yrot += dx * TOUCH_SCALE;
         
         //Log.d("MYDEBUG", "xrot:"+xrot+" yrot:"+ yrot);
        } 
        
        //Remember the values
        oldX = x;
        oldY = y;
        
  return true;
 }
 
 public void setZtranslate(float depthMove) {
  z += depthMove;
 }
 
 public void setLight() {
  light = !light;
 }
 
 public void setFilter() {
  filter += 1;
  if(filter > 2) {
   filter = 0;
  }
 }
 
 public void setBlend() {
  blend = !blend;
 }
 
 public void setReset() {
  xrot = 0;
  yrot = 0;
 }
}

cube

 public class cube {
 /** The buffer holding the vertices */
 private FloatBuffer vertexBuffer;
 /** The buffer holding the texture coordinates */
 private FloatBuffer textureBuffer;
 /** The buffer holding the indices */
 private ByteBuffer indexBuffer;
 /** The buffer holding the normals */
 private FloatBuffer normalBuffer;
 /** Our texture pointer */
 private int[] textures = new int[3];
 /** The initial vertex definition */
 private float vertices[] = {
   // Vertices according to faces
   -0.5f, -0.5f,  0.5f,
   0.5f, -0.5f,  0.5f, 
   0.5f,  0.5f,  0.5f, 
   -0.5f,  0.5f,  0.5f, 
   0.5f, -0.5f,  0.5f, 
   0.5f, -0.5f, -0.5f, 
   0.5f,  0.5f, -0.5f, 
   0.5f,  0.5f,  0.5f, 
   0.5f, -0.5f, -0.5f, 
   -0.5f, -0.5f, -0.5f, 
   -0.5f,  0.5f, -0.5f, 
   0.5f,  0.5f, -0.5f, 
   -0.5f, -0.5f, -0.5f,  
   -0.5f, -0.5f,  0.5f, 
   -0.5f,  0.5f,  0.5f, 
   -0.5f,  0.5f, -0.5f, 
   -0.5f,  0.5f,  0.5f, 
   0.5f,  0.5f,  0.5f, 
   0.5f,  0.5f, -0.5f, 
   -0.5f,  0.5f, -0.5f, 
   -0.5f, -0.5f,  0.5f, 
   0.5f, -0.5f,  0.5f, 
   0.5f, -0.5f, -0.5f, 
   -0.5f, -0.5f, -0.5f, 
 };
 /** The initial normals for the lighting calculations */ 
 private float normals[] = {
   //Normals
   // Front face
   0.0f, 0.0f, 1.0f,       
   0.0f, 0.0f, 1.0f, 
   0.0f, 0.0f, 1.0f, 
   0.0f, 0.0f, 1.0f, 
   // Right face  
   1.0f, 0.0f, 0.0f, 
   1.0f, 0.0f, 0.0f, 
   1.0f, 0.0f, 0.0f, 
   1.0f, 0.0f, 0.0f, 
   // Back face
   0.0f, 0.0f, -1.0f, 
   0.0f, 0.0f, -1.0f, 
   0.0f, 0.0f, -1.0f, 
   0.0f, 0.0f, -1.0f, 
   // Left face
   -1.0f, 0.0f, 0.0f, 
   -1.0f, 0.0f, 0.0f, 
   -1.0f, 0.0f, 0.0f, 
   -1.0f, 0.0f, 0.0f, 
   // Bottom face
   0.0f, -1.0f, 0.0f, 
   0.0f, -1.0f, 0.0f, 
   0.0f, -1.0f, 0.0f, 
   0.0f, -1.0f, 0.0f, 
   // Up face
   0.0f, 1.0f, 0.0f, 
   0.0f, 1.0f, 0.0f, 
   0.0f, 1.0f, 0.0f, 
   0.0f, 1.0f, 0.0f, 
 };
 /** The initial texture coordinates (u, v) */ 
 private float texture[] = {
   //Mapping coordinates for the vertices
   0, 1,
   1, 1,
   1, 0,
   0, 0,
   0, 1,
   1, 1,
   1, 0,
   0, 0,
   0, 1,
   1, 1,
   1, 0,
   0, 0,
   0, 1, 
   1, 1,
   1, 0,
   0, 0,
   0, 1,
   1, 1,
   1, 0,
   0, 0,
   0, 1,
   1, 1,
   1, 0,
   0, 0
 };
 /** The initial indices definition */
 private byte indices[] = {
   // Faces definition
   /*0, 1, 3, 0, 3, 2,   // Face front
   4, 5, 7, 4, 7, 6,   // Face right
   8, 9, 11, 8, 11, 10,  // ...
   12, 13, 15, 12, 15, 14, 
   16, 17, 19, 16, 19, 18, 
   20, 21, 23, 20, 23, 22,*/
   0, 1, 3, 1, 2, 3,
   4, 5, 7, 5, 6, 7,
   8, 9, 11, 9, 10, 11,
   12, 13, 15, 13, 14, 15,
   16, 17, 19, 17, 18, 19,
   20, 21, 23, 21, 22, 23,
 };
 /**
  * The Cube constructor.
  * 
  * Initiate the buffers.
  */
 public cube() {
  //
  ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
  byteBuf.order(ByteOrder.nativeOrder());
  vertexBuffer = byteBuf.asFloatBuffer();
  vertexBuffer.put(vertices);
  vertexBuffer.position(0);
  //
  byteBuf = ByteBuffer.allocateDirect(texture.length * 4);
  byteBuf.order(ByteOrder.nativeOrder());
  textureBuffer = byteBuf.asFloatBuffer();
  textureBuffer.put(texture);
  textureBuffer.position(0);
  //
  byteBuf = ByteBuffer.allocateDirect(normals.length * 4);
  byteBuf.order(ByteOrder.nativeOrder());
  normalBuffer = byteBuf.asFloatBuffer();
  normalBuffer.put(normals);
  normalBuffer.position(0);
  //
  indexBuffer = ByteBuffer.allocateDirect(indices.length);
  indexBuffer.put(indices);
  indexBuffer.position(0);
 }
 /**
  * The object own drawing function.
  * Called from the renderer to redraw this instance
  * with possible changes in values.
  * 
  * @param gl - The GL Context
  * @param filter - Which texture filter to be used
  */
 public void draw(GL10 gl, int filter) {
  //Bind the texture according to the set texture filter
  gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[filter]);
  //Enable the vertex, texture and normal state
  gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
  gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
  gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
  //Set the face rotation
  gl.glFrontFace(GL10.GL_CCW);
  //Point to our buffers
  gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
  gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
  gl.glNormalPointer(GL10.GL_FLOAT, 0, normalBuffer);
  //Draw the vertices as triangles, based on the Index Buffer information
  gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);
  //Disable the client state before leaving
  gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
  gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
  gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
 }
 /**
  * Load the textures
  * 
  * @param gl - The GL Context
  * @param context - The Activity context
  */
 public void loadGLTexture(GL10 gl, Context context) {
  //Get the texture from the Android resource directory
  InputStream is = context.getResources().openRawResource(R.drawable.pae002);
  Bitmap bitmap = null;
  try {
   //BitmapFactory is an Android graphics utility for images
   bitmap = BitmapFactory.decodeStream(is);
   // 화면 돌리기
   if(bitmap.getWidth() > bitmap.getHeight()) {
    Matrix matrix = new Matrix();
    matrix.postRotate(90);
    Bitmap resized = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    bitmap = resized;
   }
   //Log.d("MYDEBUG", "bitmap size : "+bitmap.getWidth() + ", " + bitmap.getHeight());
  } finally {
   //Always clear and close
   try {
    is.close();
    is = null;
   } catch (IOException e) {
   }
  }
  //Generate there texture pointer
  gl.glGenTextures(3, textures, 0);
  //Create Nearest Filtered Texture and bind it to texture 0
  gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_NEAREST);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
  GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
  //Create Linear Filtered Texture and bind it to texture 1
  gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[1]);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
  GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
  //Create mipmapped textures and bind it to texture 2
  gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[2]);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_NEAREST);
  /*
   * This is a change to the original tutorial, as buildMipMap does not exist anymore
   * in the Android SDK.
   * 
   * We check if the GL context is version 1.1 and generate MipMaps by flag.
   * Otherwise we call our own buildMipMap implementation
   */
  if(gl instanceof GL11) {
   gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE);
   GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
   //
  } else {
   buildMipmap(gl, bitmap);
  } 
  //Clean up
  bitmap.recycle();
 }
 /**
  * Our own MipMap generation implementation.
  * Scale the original bitmap down, always by factor two,
  * and set it as new mipmap level.
  * 
  * Thanks to Mike Miller (with minor changes)!
  * 
  * @param gl - The GL Context
  * @param bitmap - The bitmap to mipmap
  */
 private void buildMipmap(GL10 gl, Bitmap bitmap) {
  //
  int level = 0;
  //
  int height = bitmap.getHeight();
  int width = bitmap.getWidth();
  //
  while(height >= 1 || width >= 1) {
   //First of all, generate the texture from our bitmap and set it to the according level
   GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bitmap, 0);
   //
   if(height == 1 || width == 1) {
    break;
   }
   //Increase the mipmap level
   level++;
   //
   height /= 2;
   width /= 2;
   Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true);
   //Clean up
   bitmap.recycle();
   bitmap = bitmap2;
  }
 }
}