4

我一直在 Stack Overflow 中寻找 OpenGL ES 中 2D 选择的介绍。我主要看到有关 3D 的问题。

我正在使用 OpenGL ES 在 Android 4.0.3 上设计一个基于 2D 瓦片的关卡编辑器。在关卡编辑器中,有一个 2D 黄色方形对象放置在屏幕中央。我想要的只是检测对象是否已被用户触摸。

在此处输入图像描述

在关卡编辑器中,没有任何瓷砖重叠。相反,它们并排放置,就像 MS Paint 中位图图像中的两个附近像素一样。我的目的是单独检测关卡编辑器中每个方形对象的触摸事件。

该对象是用一个简单的顶点数组创建的,并使用 GL_TRIANGLES 来绘制 2 个平面直角三角形。没有任何操作,也没有从文件或任何东西加载。我唯一知道的是,如果用户触摸任何一个黄色三角形,那么两个黄色三角形都将被选中。

任何人都可以提供有关我需要如何执行此操作的提示吗?提前致谢。

编辑:

这是draw()功能:

public void draw(GL10 gl) {
    gl.glPushMatrix();
    gl.glTranslatef(-(deltaX - translateX), (deltaY - translateY), 1f);
    gl.glColor4f(1f, 1f, 0f, 1f);
    //TODO: Move ClientState and MatrixStack outside of draw().
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertices);
    gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 6);
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glPopMatrix();
}

编辑2:

我仍然缺少一些信息。你在用相机吗?还是在模型渲染之前推送其他矩阵?例如,如果您使用的是正交相机,您可以像这样轻松地取消投影屏幕坐标 [x_screen, y_screen](y 类似):

我没有使用相机,但我可能使用的是正交投影。再说一次,我不知道,因为我只是使用一个通用的 OpenGL 函数。我会推送和弹出矩阵,因为我计划将许多瓷砖(方形 2D 对象)与不同的平移矩阵集成在一起。没有两个图块具有相同的平移矩阵 M。

在 2D 方面,透视投影与正交投影相同吗?我看不出两者之间有任何区别。

这是创建表面时的初始设置(扩展GLSurfaceView和实现的类GLSurfaceView.Renderer):

public void onSurfaceChanged(GL10 gl, int width, int height) {
    gl.glViewport(0, 0, width, height);
}

public void onSurfaceCreated(GL10 gl, EGLConfig arg1) {
    reset();
}
public void onDrawFrame(GL10 gl) {
    clearScreen(gl);
    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glLoadIdentity();
    gl.glOrthof(0f, super.getWidth(), 0f, super.getHeight(), 1, -1);
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
    canvas.draw(gl);
}

private void clearScreen(GL10 gl) {
    gl.glClearColor(0.5f, 1f, 1f, 1f);
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
}
4

3 回答 3

2

基本方法如下:

  1. 为每个“可触摸”对象定义一个边界框。这可能只是一个矩形(x、y、宽度、高度)。
  2. 当你在世界中更新一个瓦片时,你会更新它的边界框(完全在世界坐标中)。
  3. 当用户触摸屏幕时,您必须将屏幕坐标取消投影到世界坐标
  4. 检查未投影点是否与任何边界框重叠。

关于上一个项目的一些提示。[已编辑]

  • 1 和 2。您应该跟踪渲染图块的位置。存储它们的位置和大小。矩形是一种方便的结构。在您的示例中,可以这样计算。当模型改变时,你必须重新计算它。让我们称之为矩形 r:

    r.x = yourTile.position.x -(deltaX - translateX)  
    r.y = yourTile.position.y -(deltaY - translateY)
    r.width= yourTile.width  //as there is no model scaling
    r.height = yourTile.height//
    
  • 3 - 如果您使用的是正交相机,您可以像这样轻松地取消投影屏幕坐标 [x_screen, y_screen](y 是类似的):

    x_model = ((x_screen/GL_viewport_width) -0.5 )*camera.WIDTH + Camera.position.x
    
  • 4 - 对于每个矩形检查 [x_model; y_model] 在里面。

[第二次编辑]通过更新矩阵的方式,您可以考虑使用位置为surfaceView.width()/2、surfaceView.height()/2 的相机。您将屏幕上的 1 个像素与世界上的 1 个单位匹配,因此您不需要取消投影任何东西。您可以在我的公式中替换该值并获得 x_screen = x_model - (您需要翻转触摸事件的 Y 分量,因为 Y 在 Java 中向下增长,而在 GL 中向上增长)。

最后的话。如果用户触摸点 [x,y] 检查 [x, screenHeight-y]* 是否击中您的一些矩形,您就完成了。做一些调试,记录接触点,看看它们是否符合预期。生成您的矩形并查看它们是否与您在屏幕上看到的相匹配,然后检查一个点是否在矩形内。

我必须告诉你,你不应该将相机设置为屏幕尺寸,因为你的应用在不同的设备上看起来会有很大的不同。这是一个独立的话题,所以我不会再进一步​​,但考虑根据世界单位定义您的模型 - 独立于屏幕尺寸。这太离题了,但我希望你已经很好地了解了你需要知道的内容!

*我告诉你的翻转。PS:坚持使用正交投影(透视会更复杂)。

于 2012-12-19T12:34:45.473 回答
1

请允许我对您的问题发表第二个答案。这完全是更高级/更哲学的。可能是一个愚蠢,无用的答案,但是,我希望它可以帮助刚接触计算机图形的人将其思想转变为“图形模式”。

您无法真正选择屏幕上的三角形。那个正方形不是2个三角形。那个正方形只是一堆黄色像素。OpenGL 获取一些顶点,连接它们,处理它们并为屏幕上的一些像素着色。在图形管道的一个阶段,甚至几何信息都丢失了,您只有孤立的像素。这类似于打印机在纸上打印的一封信。您通常不会处理来自论文的信息(好吧,也许条形码阅读器会:D)

如果您需要进一步处理您的图纸,您必须对它们进行建模并使用辅助数据结构自行处理它们。这就是为什么我建议您创建一个矩形来模拟您的瓷砖。您创建您想象中的对象“世界”,然后将它们渲染到屏幕上。用户触摸事件不属于同一个世界,因此您必须将屏幕坐标“转换”为您的世界坐标。然后你改变你的世界中的一些东西(可能是用户拖动她的手指,你必须移动一个对象),然后再次告诉 OpenGL 将你的世界渲染到屏幕上。

您应该对模型进行操作,而不是视图。网格更像是一种视图,因此您不应将它们与模型信息混合,将两者分开是一种很好的做法。(请专家指正,我是个图形爱好者)

于 2012-12-19T20:20:27.787 回答
0

你检查过 LibGDX吗?

使用 OpenGL ES 让生活变得更加轻松。

于 2012-12-19T11:36:27.460 回答