Android OpenGL ES 在触摸时添加对象

发布于 2024-12-12 08:32:27 字数 6006 浏览 0 评论 0原文

我正在构建一个小型 Android 应用程序,它将在用户触摸时添加一个立方体。 z 深度始终为 -10,屏幕始终处于横向模式。这个问题似乎被问了很多次,但我无法运行它,请原谅我,因为我是 opengl 的新手。 我对与 gluUnproject 一起使用的屏幕坐标/窗口坐标/对象坐标感到非常困惑。据我了解,屏幕是用户触摸时的,我们甚至可以从运动中获得 x 和 y。窗口坐标是加载单位坐标时的坐标,对象坐标是对单位矩阵进行变换得到对象坐标时的坐标。是这样吗?

这是我的代码,矩阵堆叠来自 android api 示例。请指出我做错了什么。


绘图部分:

public void draw(GL10 gl) {
    for (GLObject glObject : list) {
        if (glObject != null) {
            gl.glLoadIdentity();
            glObject.draw(gl);
        }
    }
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
    if (isTouching) {
        boolean addObject = false;
        for (GLObject glObject : list) {
            addObject = glObject.checkTouch(gl, x, y);
        }
        if (!addObject) {
            i++;
            Log.d("i", i + "");
            addGLObject(gl);
        }
        isTouching = false;
    }
}

onDraw的代码

private void getMatrix(GL10 gl, int mode, float[] mat) {
    GLView.matrixTrackingGL.glMatrixMode(mode);
    GLView.matrixTrackingGL.getMatrix(mat, 0);
}
public void addGLObject(GL10 gl) {
    float[] XY = getWorldCoordinate(gl, x, y);

    if (XY != null) {
//          XY[0] = (float) (x - Main.SCREEN_WIDTH / 2) / 10;
//
//          XY[1] = (float) (Main.SCREEN_HEIGHT / 2 - y) / 10;

        GLObject glObject = new GLObject(colors, XY[0], XY[1]);
        Log.d("Object position", "X: " + XY[0] + " Y: " + XY[1]);
        list.add(glObject);
    }
}
private float[] getWorldCoordinate(GL10 gl, int x, int y) {
    float[] modelMatrix = new float[16];
    float[] projMatrix = new float[16];
    int[] viewport = {0, 0, Main.SCREEN_WIDTH, Main.SCREEN_HEIGHT};


    getMatrix(gl, GL10.GL_MODELVIEW, modelMatrix);
    getMatrix(gl, GL10.GL_PROJECTION, projMatrix);

    float[] output = new float[4];
    GLU.gluUnProject(x, viewport[1] + viewport[3] - y, -10, modelMatrix, 0, projMatrix, 0, viewport, 0, output, 0);
    return new float[] {output[0]/output[3], output[1]/output[3]};
}

public class GLObject {
    private float[] vertices = { 1.000000f, 1.000000f, -1.000000f, 1.000000f,
    -1.000000f, -1.000000f, -1.000000f, -1.000000f, -1.000000f,
    -1.000000f, 1.000000f, -1.000000f, 1.000000f, 1.000000f, 1.000000f,
    1.000000f, -1.000001f, 1.000000f, -1.000000f, -1.000000f,
    1.000000f, -1.000000f, 1.000000f, 1.000000f, };
private short[] faces = { 0, 1, 2, 0, 2, 3, 4, 7, 6, 4, 6, 5, 0, 4, 5, 0,
    5, 1, 1, 5, 6, 1, 6, 2, 2, 6, 7, 2, 7, 3, 4, 0, 3, 4, 3, 7 };
private float[] colors;
private float[] rot = { 0.0f, 0.0f, 0.0f };
private Float positionX, positionY;
private int alpha = 0;

// Our vertex buffer.
private FloatBuffer vertexBuffer;

// Our index buffer.
private ShortBuffer faceBuffer;

public GLObject() {
    init();
}

public GLObject(float[] colors, float x, float y) {
    this.colors = colors.clone();
    this.positionX = x;
    this.positionY = y;

    if (positionX.intValue() % 2 == 0) {
        rot[0] = 1.0f;
    } else {
        if (positionY.intValue() % 2 == 0) {
    rot[1] = 1.0f;
    } else {
        rot[2] = 1.0f;
    }
    }
    init();
}

private void init() {
    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
    vbb.order(ByteOrder.nativeOrder());
    vertexBuffer = vbb.asFloatBuffer();
    vertexBuffer.put(vertices);
    vertexBuffer.position(0);

    ByteBuffer ibb = ByteBuffer.allocateDirect(faces.length * 2);
    ibb.order(ByteOrder.nativeOrder());
    faceBuffer = ibb.asShortBuffer();
    faceBuffer.put(faces);
    faceBuffer.position(0);
}

public boolean checkTouch(GL10 gl, int x, int y) {
    boolean isTouched = false;
    ByteBuffer pixels = ByteBuffer.allocate(4);

    gl.glReadPixels(x, Main.SCREEN_HEIGHT - y, 1, 1, GL10.GL_RGBA,
            GL10.GL_UNSIGNED_BYTE, pixels);
    Log.d("COLOR",
            pixels.get(0) + " " + pixels.get(1) + " " + pixels.get(2) + " "
                    + pixels.get(3));
            // isTouched always false to test always add object to screen
    return isTouched;
}

public void draw(GL10 gl) {
    // Counter-clockwise winding.
    gl.glFrontFace(GL10.GL_CCW); // OpenGL docs
    // Enable face culling.
    gl.glEnable(GL10.GL_CULL_FACE); // OpenGL docs
    // What faces to remove with the face culling.
    gl.glCullFace(GL10.GL_BACK); // OpenGL docs

    // Enabled the vertices buffer for writing and to be used during
    // rendering.
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// OpenGL docs.
    // Enable color
    gl.glColor4f(colors[0], colors[1], colors[2], 1.0f);
    // Specifies the location and data format of an array of vertex
    // coordinates to use when rendering.
    gl.glPushMatrix();
    gl.glTranslatef(positionX, positionY, -10);
    // rotate
    alpha += 1;
    gl.glRotatef(alpha, rot[0], rot[1], rot[2]);
    // draw
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, // OpenGL docs
            vertexBuffer);

    gl.glDrawElements(GL10.GL_TRIANGLES, faces.length,// OpenGL docs
            GL10.GL_UNSIGNED_SHORT, faceBuffer);
    gl.glPopMatrix();
    // Disable the vertices buffer.
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // OpenGL docs
    // Disable face culling.
    gl.glDisable(GL10.GL_CULL_FACE); // OpenGL docs
}

下面是添加对象}


public void onDrawFrame(GL10 gl) {
        // TODO Auto-generated method stub
        // Clears the screen and depth buffer.
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | // OpenGL docs.
                GL10.GL_DEPTH_BUFFER_BIT);
        gl.glMatrixMode(GL10.GL_PROJECTION);
        // Reset the projection matrix
        gl.glLoadIdentity();
        GLU.gluPerspective(gl, 90.0f, Main.SCREEN_WIDTH/Main.SCREEN_HEIGHT, 3.0f, 100.0f); 
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
        GLU.gluLookAt(gl, 4.0f, 2.0f, 1.0f, 
                0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);    
        // draw object
        glObjectManager.draw(gl);
    }

I am building a small Android application which will add a cube on user's touch. The z depth is always -10, screen is always in landscape mode. This question seems to be asked many times, but I cannot get it running, forgive me as I am newbie to opengl.
I am quite confused about the screen coordinate/window coordinate/object coordinate to use with the gluUnproject. As I understand, screen is when user touch and we get x and y from motion even. Window coordinate is when we load the identity, and object coordinate is when we transform the identity matrix to get object's coordinate. Is that right?

And here is my code, the matrix stacking is from android api sample. Please point out what I am doing wrong.


The drawing part:

public void draw(GL10 gl) {
    for (GLObject glObject : list) {
        if (glObject != null) {
            gl.glLoadIdentity();
            glObject.draw(gl);
        }
    }
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
    if (isTouching) {
        boolean addObject = false;
        for (GLObject glObject : list) {
            addObject = glObject.checkTouch(gl, x, y);
        }
        if (!addObject) {
            i++;
            Log.d("i", i + "");
            addGLObject(gl);
        }
        isTouching = false;
    }
}

Here is the code for adding object

private void getMatrix(GL10 gl, int mode, float[] mat) {
    GLView.matrixTrackingGL.glMatrixMode(mode);
    GLView.matrixTrackingGL.getMatrix(mat, 0);
}
public void addGLObject(GL10 gl) {
    float[] XY = getWorldCoordinate(gl, x, y);

    if (XY != null) {
//          XY[0] = (float) (x - Main.SCREEN_WIDTH / 2) / 10;
//
//          XY[1] = (float) (Main.SCREEN_HEIGHT / 2 - y) / 10;

        GLObject glObject = new GLObject(colors, XY[0], XY[1]);
        Log.d("Object position", "X: " + XY[0] + " Y: " + XY[1]);
        list.add(glObject);
    }
}
private float[] getWorldCoordinate(GL10 gl, int x, int y) {
    float[] modelMatrix = new float[16];
    float[] projMatrix = new float[16];
    int[] viewport = {0, 0, Main.SCREEN_WIDTH, Main.SCREEN_HEIGHT};


    getMatrix(gl, GL10.GL_MODELVIEW, modelMatrix);
    getMatrix(gl, GL10.GL_PROJECTION, projMatrix);

    float[] output = new float[4];
    GLU.gluUnProject(x, viewport[1] + viewport[3] - y, -10, modelMatrix, 0, projMatrix, 0, viewport, 0, output, 0);
    return new float[] {output[0]/output[3], output[1]/output[3]};
}

public class GLObject {
    private float[] vertices = { 1.000000f, 1.000000f, -1.000000f, 1.000000f,
    -1.000000f, -1.000000f, -1.000000f, -1.000000f, -1.000000f,
    -1.000000f, 1.000000f, -1.000000f, 1.000000f, 1.000000f, 1.000000f,
    1.000000f, -1.000001f, 1.000000f, -1.000000f, -1.000000f,
    1.000000f, -1.000000f, 1.000000f, 1.000000f, };
private short[] faces = { 0, 1, 2, 0, 2, 3, 4, 7, 6, 4, 6, 5, 0, 4, 5, 0,
    5, 1, 1, 5, 6, 1, 6, 2, 2, 6, 7, 2, 7, 3, 4, 0, 3, 4, 3, 7 };
private float[] colors;
private float[] rot = { 0.0f, 0.0f, 0.0f };
private Float positionX, positionY;
private int alpha = 0;

// Our vertex buffer.
private FloatBuffer vertexBuffer;

// Our index buffer.
private ShortBuffer faceBuffer;

public GLObject() {
    init();
}

public GLObject(float[] colors, float x, float y) {
    this.colors = colors.clone();
    this.positionX = x;
    this.positionY = y;

    if (positionX.intValue() % 2 == 0) {
        rot[0] = 1.0f;
    } else {
        if (positionY.intValue() % 2 == 0) {
    rot[1] = 1.0f;
    } else {
        rot[2] = 1.0f;
    }
    }
    init();
}

private void init() {
    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
    vbb.order(ByteOrder.nativeOrder());
    vertexBuffer = vbb.asFloatBuffer();
    vertexBuffer.put(vertices);
    vertexBuffer.position(0);

    ByteBuffer ibb = ByteBuffer.allocateDirect(faces.length * 2);
    ibb.order(ByteOrder.nativeOrder());
    faceBuffer = ibb.asShortBuffer();
    faceBuffer.put(faces);
    faceBuffer.position(0);
}

public boolean checkTouch(GL10 gl, int x, int y) {
    boolean isTouched = false;
    ByteBuffer pixels = ByteBuffer.allocate(4);

    gl.glReadPixels(x, Main.SCREEN_HEIGHT - y, 1, 1, GL10.GL_RGBA,
            GL10.GL_UNSIGNED_BYTE, pixels);
    Log.d("COLOR",
            pixels.get(0) + " " + pixels.get(1) + " " + pixels.get(2) + " "
                    + pixels.get(3));
            // isTouched always false to test always add object to screen
    return isTouched;
}

public void draw(GL10 gl) {
    // Counter-clockwise winding.
    gl.glFrontFace(GL10.GL_CCW); // OpenGL docs
    // Enable face culling.
    gl.glEnable(GL10.GL_CULL_FACE); // OpenGL docs
    // What faces to remove with the face culling.
    gl.glCullFace(GL10.GL_BACK); // OpenGL docs

    // Enabled the vertices buffer for writing and to be used during
    // rendering.
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// OpenGL docs.
    // Enable color
    gl.glColor4f(colors[0], colors[1], colors[2], 1.0f);
    // Specifies the location and data format of an array of vertex
    // coordinates to use when rendering.
    gl.glPushMatrix();
    gl.glTranslatef(positionX, positionY, -10);
    // rotate
    alpha += 1;
    gl.glRotatef(alpha, rot[0], rot[1], rot[2]);
    // draw
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, // OpenGL docs
            vertexBuffer);

    gl.glDrawElements(GL10.GL_TRIANGLES, faces.length,// OpenGL docs
            GL10.GL_UNSIGNED_SHORT, faceBuffer);
    gl.glPopMatrix();
    // Disable the vertices buffer.
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); // OpenGL docs
    // Disable face culling.
    gl.glDisable(GL10.GL_CULL_FACE); // OpenGL docs
}

}


onDraw:

public void onDrawFrame(GL10 gl) {
        // TODO Auto-generated method stub
        // Clears the screen and depth buffer.
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | // OpenGL docs.
                GL10.GL_DEPTH_BUFFER_BIT);
        gl.glMatrixMode(GL10.GL_PROJECTION);
        // Reset the projection matrix
        gl.glLoadIdentity();
        GLU.gluPerspective(gl, 90.0f, Main.SCREEN_WIDTH/Main.SCREEN_HEIGHT, 3.0f, 100.0f); 
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
        GLU.gluLookAt(gl, 4.0f, 2.0f, 1.0f, 
                0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);    
        // draw object
        glObjectManager.draw(gl);
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

帥小哥 2024-12-19 08:32:27

它与横向模式无关,问题是您在 z 轴上将立方体平移 -10。尝试将值设置为 -100,所有立方体都将位于中心。然后尝试将 0 作为 z 值 (x, y, 0)。立方体将距离屏幕中心更远,并且更接近您期望的位置。

看看http://tle.tafevc.com.au/toolbox/file/9495cce8-17b5-a8a5-d9b3-47c0c142d88d/1/sketches_and_drawings_lo.zip/3204a_20_reading_drawings/images/brick_perspective.jpg透视投影的一个例子。当立方体位于 z=0 时,这就是图像中的情况。但当 z=-10 时,它更靠近屏幕中心(X)并且更小,因为它沿着蓝线延伸到地平线。

It has nothing to do with landscape mode, the problem is that you are translating your cube by -10 on the z axis. Try putting values of -100 and all the cubes will be at the center. Then try putting 0 for the z value (x, y, 0). The cubes will be much further out from the center of the screen and closer to where you expect them to be.

Look at http://tle.tafevc.com.au/toolbox/file/9495cce8-17b5-a8a5-d9b3-47c0c142d88d/1/sketches_and_drawings_lo.zip/3204a_20_reading_drawings/images/brick_perspective.jpg for an example of perspective projection. When the cube is at z=0, that is what is in the image. But when z=-10, it is closer to the center of the screen (the X) and smaller, because it follows the blue lines out to the horizon.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文