如何用手指移动 OpenGL 方块? [英] How to move a OpenGL square with the finger?

查看:21
本文介绍了如何用手指移动 OpenGL 方块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

实际上,我有一个适用于 Android 1.5 的应用程序,它带有一个 GLSurfaceView 类,可以在屏幕上显示一个简单的方形多边形.

Actually I have an application for Android 1.5 with a GLSurfaceView class that shows a simple square polygon on the screen.

我想学习如何添加新功能,即用手指触摸方块移动方块的功能.我的意思是当用户触摸方块并移动手指时,方块应该粘在手指上,直到手指松开屏幕.

I want to learn how to add a new functionality, the functionality of moving the square touching it with the finger. I mean that when the user touches the square and moves the finger, the square should stick to the finger, until the finger releases the screen.

我们将不胜感激任何教程/代码示例/帮助.

Any tutorials/code examples/help will be apreciated.

我的代码:

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

这是我的广场课:

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

推荐答案

你看过Android教程代码吗?它们与 OpenGL ES 1 和 2 中的示例非常相似.

Have you looked at the Android tutorial code? They have something very similar to this with examples in OpenGL ES 1 and 2.

在 OpenGL ES 1 教程中,有一节专门用于处理触摸事件.http://developer.android.com/resources/tutorials/opengl/opengl-es10.html#touch

In the OpenGL ES 1 tutorial, there's a section just for handling touch events. http://developer.android.com/resources/tutorials/opengl/opengl-es10.html#touch

所以您想将 AddMotion 部分从 glrotatef 命令修改为 gltranslatef;

So you'd want to modify the AddMotion section from glrotatef command into gltranslatef;

编辑

看起来您对坐标转换比对象选择更感兴趣.因此,无论您在屏幕上触摸哪里,图像都会出现在哪里(与触摸和拖动图像相反,这意味着选择).你关于winZ的问题让我觉得你正在尝试gluunproject.如果是这种情况,您已经知道您的 winZ,因为您通过z"变量将相机从对象转换回来.既然你的 z 是负数,为什么不试试这个呢?

Looks like you're more interested in coordinate conversion than object selection. So, wherever you touch on the screen, that's where the image goes (as opposed to touching and dragging an image, which would imply selection). And your question about winZ makes me think you're trying gluunproject. If that's the case, you already know your winZ because you translate the camera back from the object by your "z" variable. Since your z is negative, why not try this?

假设您在活动中为 GLSurfaceView 设置了 GLWrapper:

Assuming you've set your GLWrapper for your GLSurfaceView in your activity:

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

    });

然后,在您的 GLSurfaceView/Renderer 子类中...

Then, in your GLSurfaceView/Renderer subclass...

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

然后您可以修改您的 TouchEvent 处理程序以包含

Then you can modify your TouchEvent handler to contain

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

并将下一部分放在您的 draw 方法中,然后再调用其他 translate/scale/rotation:

And put this next section in your draw method before the other translate/scale/rotation calls:

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

希望这能给你想要的结果.

Hopefully this gives you the result you want.

这篇关于如何用手指移动 OpenGL 方块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆