2011-11-04 66 views
5

Thực ra tôi có một ứng dụng cho Android 1.5 với lớp GLSurfaceView hiển thị đa giác hình vuông đơn giản trên màn hình.Cách di chuyển hình vuông OpenGL bằng ngón tay?

Tôi muốn tìm hiểu cách thêm chức năng mới, chức năng di chuyển hình vuông chạm vào hình vuông bằng ngón tay. Ý tôi là khi người dùng chạm vào hình vuông và di chuyển ngón tay, hình vuông sẽ dính vào ngón tay cho đến khi ngón tay thả màn hình ra.

Bất kỳ hướng dẫn/mã ví dụ/trợ giúp nào sẽ được apreciated.

Mã của tôi:

public class MySurfaceView extends GLSurfaceView implements Renderer { 
private Context context; 
private Square square; 
private float xrot;     //X Rotation 
private float yrot;     //Y Rotation 
private float zrot;     //Z Rotation 
private float xspeed;    //X Rotation Speed 
private float yspeed;    //Y Rotation Speed 
private float z = -1.15f;   //Profundidad en el eje Z 
private float oldX; //valor anterior de X, para rotación 
private float oldY; //valor anterior de Y, para rotación 
private final float TOUCH_SCALE = 0.2f;  //necesario para la rotación 

//create the matrix grabber object in your initialization code 
private MatrixGrabber mg = new MatrixGrabber();   

private boolean firstTimeDone=false; //true si la aplicación ya ha sido inicializada. 

public MySurfaceView(Context context, Bitmap image) { 
    super(context); 
    this.context = context; 
    setEGLConfigChooser(8, 8, 8, 8, 16, 0); //fondo transparente 
    getHolder().setFormat(PixelFormat.TRANSLUCENT); //fondo transparente 
    //Transformamos esta clase en renderizadora 
    this.setRenderer(this); 
    //Request focus, para que los botones reaccionen 
    this.requestFocus(); 
    this.setFocusableInTouchMode(true); 
    square = new Square(image);         
} 

public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
    gl.glDisable(GL10.GL_DITHER);    //dithering OFF 
    gl.glEnable(GL10.GL_TEXTURE_2D);   //Texture Mapping ON 
    gl.glShadeModel(GL10.GL_SMOOTH);   //Smooth Shading 
    gl.glClearDepthf(1.0f);      //Depth Buffer Setup 
    gl.glEnable(GL10.GL_DEPTH_TEST);   //Depth Testing ON 
    gl.glDepthFunc(GL10.GL_LEQUAL); 
    gl.glClearColor(0,0,0,0); //fondo transparente 
    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);   
    //Cargamos la textura del cubo. 
    square.loadGLTexture(gl, this.context); 
} 

public void onDrawFrame(GL10 gl) { 
    //Limpiamos pantalla y Depth Buffer 
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 
    gl.glLoadIdentity(); 
    //Dibujado 
    gl.glTranslatef(0.0f, 0.0f, z);   //Move z units into the screen 
    gl.glScalef(0.8f, 0.8f, 0.8f);   //Escalamos para que quepa en la pantalla 
    //Rotamos sobre los ejes. 
    gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f); //X 
    gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f); //Y 
    gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f); //Z 
    //Dibujamos el cuadrado 
    square.draw(gl);  
    //Factores de rotación. 
    xrot += xspeed; 
    yrot += yspeed;   


    if (!firstTimeDone) 
    {  
     /////////////// NEW CODE FOR SCALING THE AR IMAGE TO THE DESIRED WIDTH /////////////////    
     mg.getCurrentProjection(gl); 
     mg.getCurrentModelView(gl);      
     float [] modelMatrix = new float[16]; 
     float [] projMatrix = new float[16]; 
     modelMatrix=mg.mModelView; 
     projMatrix=mg.mProjection;   
     int [] mView = new int[4]; 
     mView[0] = 0; 
     mView[1] = 0; 
     mView[2] = 800; //width 
     mView[3] = 480; //height 
     float [] outputCoords = new float[3]; 
     GLU.gluProject(-1.0f, -1.0f, z, modelMatrix, 0, projMatrix, 0, mView, 0, outputCoords, 0); 

     int i=0; 
     System.out.print(i); 
     // firstTimeDone=true; 
    } 
} 

//si el surface cambia, resetea la vista, imagino que esto pasa cuando cambias de modo portrait/landscape o sacas el teclado físico en móviles tipo Droid. 
public void onSurfaceChanged(GL10 gl, int width, int height) { 
    if(height == 0) {      
     height = 1;       
    } 
    gl.glViewport(0, 0, width, height);  //Reset Viewport 
    gl.glMatrixMode(GL10.GL_PROJECTION); //Select Projection Matrix 
    gl.glLoadIdentity();     //Reset Projection Matrix 
    //Aspect Ratio de la ventana 
    GLU.gluPerspective(gl, 45.0f, (float)width/(float)height, 0.1f, 100.0f); 
    gl.glMatrixMode(GL10.GL_MODELVIEW);  //Select Modelview Matrix 
    gl.glLoadIdentity();     //Reset Modelview Matrix   

} 

public boolean onTouchEvent(MotionEvent event) { 
    float x = event.getX(); 
    float y = event.getY(); 
    switch (event.getAction()) 
    { 
     case MotionEvent.ACTION_MOVE: 
      //Calculamos el cambio 
      float dx = x - oldX; 
      float dy = y - oldY; 
      xrot += dy * TOUCH_SCALE; 
      yrot += dx * TOUCH_SCALE; 
      //Log.w("XXXXXX", "ACTION_MOVE_NO_ZOOM"); 
      break; 
    } 
    oldX = x; 
    oldY = y; 
    return true; //El evento ha sido manejado 
} 

public void zoomIn(){ 
    z=z+0.2f; 
    if (z>-1.0f) 
     z=-1.0f; 
} 
public void zoomOut(){ 
    z=z-0.2f; 
    if (z<-20.0f) 
     z=-20.0f; 
} 
public void rotateL(){ 
    zrot=zrot+3.0f; 
} 
public void rotateR(){ 
    zrot=zrot-3.0f; 
} 
public void reset() 
{ 
    xrot=0; 
    yrot=0; 
    zrot=0; 
    xspeed=0; 
    yspeed=0; 
    z = -5.0f; 
} 
} 

Đây là lớp vuông của tôi:

public class Square { 
//Buffer de vertices 
private FloatBuffer vertexBuffer; 
//Buffer de coordenadas de texturas 
private FloatBuffer textureBuffer; 
//Puntero de texturas 
private int[] textures = new int[3]; 
//El item a representar 
private Bitmap image; 
//Definición de vertices 

private float vertices[] = 
{ 
    -1.0f, -1.0f, 0.0f,  //Bottom Left 
    1.0f, -1.0f, 0.0f,  //Bottom Right 
    -1.0f, 1.0f, 0.0f,  //Top Left 
    1.0f, 1.0f, 0.0f  //Top Right 
}; 
/* 
private float vertices[] = 
{ 
-0.8f, -0.8f, 0.0f,  //Bottom Left 
0.8f, -0.8f, 0.0f,  //Bottom Right 
-0.8f, 0.8f, 0.0f,  //Top Left 
0.8f, 0.8f, 0.0f 
}; 
*/ 
//Coordenadas (u, v) de las texturas  
/* 
private float texture[] = 
{   
    //Mapping coordinates for the vertices 
    0.0f, 0.0f, 
    0.0f, 1.0f, 
    1.0f, 0.0f, 
    1.0f, 1.0f 
}; 
*/ 
private float texture[] = 
{ 
    //Mapping coordinates for the vertices 
    0.0f, 1.0f, 
    1.0f, 1.0f, 
    0.0f, 0.0f, 
    1.0f, 0.0f 
}; 
//Inicializamos los buffers 
public Square(Bitmap image) { 
    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); 

    this.image=image; 
} 
//Funcion de dibujado 
public void draw(GL10 gl) { 
    gl.glFrontFace(GL10.GL_CCW); 
    //gl.glEnable(GL10.GL_BLEND); 
    //Bind our only previously generated texture in this case 
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); 
    //Point to our vertex buffer 
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); 
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer); 
    //Enable vertex buffer 
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
    //Draw the vertices as triangle strip 
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length/3); 
    //Disable the client state before leaving 
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); 
    //gl.glDisable(GL10.GL_BLEND);  
} 
//Carga de texturas 
public void loadGLTexture(GL10 gl, Context context) { 
    //Generamos un puntero de texturas 
    gl.glGenTextures(1, textures, 0);  
    //y se lo asignamos a nuestro array 
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); 
    //Creamos filtros de texturas 
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); 
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 
    //Diferentes parametros de textura posibles GL10.GL_CLAMP_TO_EDGE 
    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);  
    /* 
    String imagePath = "radiocd5.png"; 
    AssetManager mngr = context.getAssets(); 
    InputStream is=null; 
    try { 
     is = mngr.open(imagePath); 
    } catch (IOException e1) { e1.printStackTrace(); } 
    */ 
    //Get the texture from the Android resource directory 
    InputStream is=null; 
    /* 
    if (item.equals("rim")) 
     is = context.getResources().openRawResource(R.drawable.rueda); 
    else if (item.equals("selector")) 
     is = context.getResources().openRawResource(R.drawable.selector); 
    */  
    /* 
    is = context.getResources().openRawResource(resourceId); 
    Bitmap bitmap = null; 
    try { 
     bitmap = BitmapFactory.decodeStream(is); 
    } finally { 
     try { 
      is.close(); 
      is = null; 
     } catch (IOException e) { 
     } 
    } 
    */ 
    Bitmap bitmap =image;  
    //con el siguiente código redimensionamos las imágenes que sean mas grandes de 256x256. 
    int newW=bitmap.getWidth(); 
    int newH=bitmap.getHeight(); 
    float fact; 
    if (newH>256 || newW>256) 
    { 
     if (newH>256) 
     { 
      fact=(float)255/(float)newH; //porcentaje por el que multiplicar para ser tamaño 256 
      newH=(int)(newH*fact); //altura reducida al porcentaje necesario 
      newW=(int)(newW*fact); //anchura reducida al porcentaje necesario 
     } 
     if (newW>256) 
     { 
      fact=(float)255/(float)newW; //porcentaje por el que multiplicar para ser tamaño 256 
      newH=(int)(newH*fact); //altura reducida al porcentaje necesario 
      newW=(int)(newW*fact); //anchura reducida al porcentaje necesario 
     } 
     bitmap=Bitmap.createScaledBitmap(bitmap, newW, newH, true); 
    }  
    //con el siguiente código transformamos imágenes no potencia de 2 en imágenes potencia de 2 (pot) 
    //meto el bitmap NOPOT en un bitmap POT para que no aparezcan texturas blancas. 
    int nextPot=256; 
    int h = bitmap.getHeight(); 
    int w = bitmap.getWidth(); 
    int offx=(nextPot-w)/2; //distancia respecto a la izquierda, para que la imagen quede centrada en la nueva imagen POT 
    int offy=(nextPot-h)/2; //distancia respecto a arriba, para que la imagen quede centrada en la nueva imagen POT 
    Bitmap bitmap2 = Bitmap.createBitmap(nextPot, nextPot, Bitmap.Config.ARGB_8888); //crea un bitmap transparente gracias al ARGB_8888 
    Canvas comboImage = new Canvas(bitmap2); 
    comboImage.drawBitmap(bitmap, offx, offy, null); 
    comboImage.save(); 

    //Usamos Android GLUtils para espcificar una textura de 2 dimensiones para nuestro bitmap 
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap2, 0); 

    //Checkeamos si el GL context es versión 1.1 y generamos los Mipmaps por Flag. Si no, llamamos a nuestra propia implementación 
    if(gl instanceof GL11) { 
     gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE); 
     GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap2, 0); 
    } else { 
     buildMipmap(gl, bitmap2); 
    } 
    //Limpiamos los bitmaps 
    bitmap.recycle(); 
    bitmap2.recycle(); 
} 
//Nuestra implementación de MipMap. Escalamos el bitmap original hacia abajo por factor de 2 y lo asignamos como nuevo nivel de mipmap 
private void buildMipmap(GL10 gl, Bitmap bitmap) { 
    int level = 0; 
    int height = bitmap.getHeight(); 
    int width = bitmap.getWidth(); 
    while(height >= 1 || width >= 1) { 
     GLUtils.texImage2D(GL10.GL_TEXTURE_2D, level, bitmap, 0); 
     if(height == 1 || width == 1) { 
      break; 
     } 
     level++; 
     height /= 2; 
     width /= 2; 
     Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, true); 
     bitmap.recycle(); 
     bitmap = bitmap2; 
    } 
} 
} 

Trả lời

5

Các bạn đã nhìn vào mã hướng dẫn Android? Họ có một cái gì đó rất giống với điều này với các ví dụ trong OpenGL ES 1 và 2.

Trong hướng dẫn OpenGL ES 1, có một phần chỉ để xử lý các sự kiện chạm. http://developer.android.com/resources/tutorials/opengl/opengl-es10.html#touch

Vì vậy, bạn muốn sửa đổi phần AddMotion từ lệnh glrotatef thành gltranslatef;

chỉnh sửa

Hình như bạn đang quan tâm nhiều hơn trong phối hợp chuyển đổi hơn lựa chọn đối tượng. Vì vậy, bất cứ nơi nào bạn chạm vào màn hình, đó là nơi mà hình ảnh đi (như trái ngược với việc chạm và kéo một hình ảnh, trong đó sẽ ngụ ý lựa chọn). Và câu hỏi của bạn về winZ làm cho tôi nghĩ rằng bạn đang cố gắng gluunproject. Nếu đó là trường hợp, bạn đã biết winZ của bạn bởi vì bạn dịch máy ảnh trở lại từ đối tượng bằng biến "z" của bạn. Vì z của bạn là âm, tại sao không thử cái này?

Giả sử bạn đã thiết GLWrapper của bạn cho GLSurfaceView của bạn trong hoạt động của bạn:

mGLView.setGLWrapper(new GLWrapper() { 
     public GL wrap(GL gl) { 
      return new MatrixTrackingGL(gl); 
     } 

    }); 

Sau đó, trong lớp con GLSurfaceView/Renderer của bạn ...

public float[] unproject(GL10 gl, float x, float y) { 
    mMatrixGrabber.getCurrentState(gl); 
    int[] view = {0,0,this.getWidth(), this.getHeight()}; 
    float[] pos = new float[4]; 
    float[] result = null; 
    int retval = GLU.gluUnProject(x, y, -z, 
      mMatrixGrabber.mModelView, 0, 
      mMatrixGrabber.mProjection, 0, 
      view, 0, 
      pos, 0); 
    if (retval != GL10.GL_TRUE) { 
     Log.e("unproject", GLU.gluErrorString(retval)); 
    } else { 
     result = new float[3]; 
     result[0] = pos[0]/pos[3]; 
     result[1] = pos[1]/pos[3]; 
     result[2] = pos[2]/pos[3]; 
     result = pos; 
    } 
    return result; 
} 

Sau đó, bạn có thể sửa đổi handler TouchEvent của bạn để chứa

switch (event.getAction()) 
    { 
     case MotionEvent.ACTION_MOVE: 
      //Calculamos el cambio 
      float dx = x - oldX; 
      float dy = y - oldY; 
      xrot += dy * TOUCH_SCALE; 
      yrot += dx * TOUCH_SCALE; 
      //Log.w("XXXXXX", "ACTION_MOVE_NO_ZOOM"); 
      touching = true; 
      break; 
     case MotionEvent.ACTION_UP: 
      xrot = 0; 
      yrot = 0; 
      zrot = 0; 
      touching = false; 
      break; 
    } 

Và đặt phần tiếp theo này trong phương pháp vẽ của bạn trước các cuộc gọi dịch/quy mô/xoay khác:

if (touching) { 
     float[] point = unproject(gl, oldX, (this.getHeight() - oldY)); 
     if (point == null) { 
      Log.e("Draw", "No Point"); 
     } else { 
      gl.glTranslatef(point[0], point[1], 0); 
     } 
    } 

Hy vọng điều này mang đến cho bạn kết quả mong muốn.

+0

vâng, tôi đã kiểm tra nó một vài giờ trước, và nó không thể giúp tôi vào nhu cầu của tôi – NullPointerException

+0

Điều gì, cụ thể, nó có thể giúp bạn không? Nó cho thấy làm thế nào để xử lý đầu vào, và sửa đổi vị trí đối tượng opengl dựa trên đầu vào. Ý của bạn là bạn muốn kéo trực tiếp đối tượng? Vì vậy, vấn đề của bạn có nhiều hơn để làm với phối hợp chuyển đổi hơn xử lý đầu vào? NẾU đó là trường hợp, bạn có thể muốn xem xét sử dụng phép chiếu chính tả 2d để chuyển đổi tọa độ phổ quát. Nếu không, bạn phải làm một số toán học để tính toán vị trí dựa trên sự thất vọng của máy ảnh với chiều sâu. – Marc

+0

Nếu bạn gặp sự cố với chuyển đổi, đây là liên kết SO cho cùng một vấn đề: http://stackoverflow.com/questions/7437482/gluunproject-android-opengl-es-1-1-usage – Marc

1

tôi sẽ thực hiện một listener ontouch chờ đợi một hành động xuống. Khi đã kích hoạt, hãy lấy vị trí của ngón tay thông qua getrawx hoặc y, và sau đó vẽ lại hình vuông trong khung hình canvas cho phù hợp. Đây là một liên kết với một hướng dẫn tốt. http://www.zdnet.com/blog/burnette/how-to-use-multi-touch-in-android-2-part-5-implementing-the-drag-gesture/1789?tag=content;siu-container

+0

không phải là dễ dàng, các tọa độ opengl không giống như x, y màn hình cordinates. Và một chút giúp đỡ nhiều hơn hai dòng sẽ được apreciated – NullPointerException

+0

Bạn có thể không dịch các cặp phối hợp vào một cái gì đó opengl có thể sử dụng? Tôi biết tôi đã làm một cái gì đó tương tự với một thư viện đồ họa khác nhau trong Android. Nó thực sự là khá dễ dàng để có được kích thước của màn hình, và bản đồ những tọa độ liên quan đến màn hình. –

+0

Tôi không thể áp dụng hướng dẫn đó vào mã của tôi, anh ấy đang sử dụng ma trận, tôi không sử dụng lớp Square với một loại triển khai khác, tôi sẽ chỉnh sửa câu hỏi của mình để thêm mã vào một vài giây – NullPointerException

Các vấn đề liên quan