在Android平台下使用OpenGLES 2.0进行基于像素的碰撞检测问题

12
这是我在这里发布的第一篇文章,如有任何错误请谅解。我正在使用OpenGL ES 2.0和Android 2.3开发一个简单的动作游戏。我目前正在开发的游戏框架基于二维精灵,存在于三维世界中。当然,我的世界实体具有诸如虚拟世界中的位置、旋转值(以float[]矩阵形式)、OpenGL纹理句柄以及Android的Bitmap句柄等信息(我不确定后者是否必要,因为我正在使用OpenGl机器进行栅格化,但暂时它就在那里,方便我使用)。这是简要的背景介绍,现在来说问题所在。
目前我卡在了基于像素的碰撞检测上,因为我不确定需要采样哪个对象(这里指OGL纹理或Android Bitmap)。我的意思是,我已经尝试过采样Android的Bitmap,但完全行不通——与读取位图外部有关的许多运行时崩溃。当然,为了能够从位图中读取像素,我使用了Bitmap.create方法来获取正确旋转的精灵。以下是代码片段:
android.graphics.Matrix m = new android.graphics.Matrix();
if(o1.angle != 0.0f) {          
    m.setRotate(o1.angle);
    b1 = Bitmap.createBitmap(b1, 0, 0, b1.getWidth(), b1.getHeight(), m, false);
}

另一个可能导致问题的问题,甚至可能是主要问题的问题,是我的交集矩形(指两个对象共同的二维空间矩形)由使用OpenGL矩阵Matrix.multiplyMV功能计算得出的两个边界框的部分组成(以下是代码)。这两种Android和OpenGL矩阵计算方法是否不相等?
Matrix.rotateM(mtxRotate, 0, -angle, 0, 0, 1);

// original bitmap size, equal to sprite size in it's model space,
// as well as in world's space
float[] rect = new float[] {
    origRect.left, origRect.top, 0.0f, 1.0f, 
    origRect.right, origRect.top, 0.0f, 1.0f,
    origRect.left, origRect.bottom, 0.0f, 1.0f,
    origRect.right, origRect.bottom, 0.0f, 1.0f 
};

android.opengl.Matrix.multiplyMV(rect, 0, mtxRotate, 0, rect, 0);
android.opengl.Matrix.multiplyMV(rect, 4, mtxRotate, 0, rect, 4);
android.opengl.Matrix.multiplyMV(rect, 8, mtxRotate, 0, rect, 8);
android.opengl.Matrix.multiplyMV(rect, 12, mtxRotate, 0, rect, 12);

// computation of object's bounding box (it is necessary as object has been
// rotated second ago and now it's bounding rectangle doesn't match it's host
float left = rect[0];
float top = rect[1];
float right = rect[0];
float bottom = rect[1];
for(int i = 4; i < 16; i += 4) {
    left = Math.min(left, rect[i]);
    top = Math.max(top, rect[i+1]);
    right = Math.max(right, rect[i]);
    bottom = Math.min(bottom, rect[i+1]);
};

一般来说,OpenGL仅用于图形处理。您不应让其接触您的游戏/世界坐标,除非要制作一个修改后的副本以呈现到屏幕上。这意味着您应该使用自己的代码计算任何边界框。同时要注意基于像素的物理系统 :) 它听起来对所有东西都是个好主意,直到您尝试并发现它只适用于不会发生物理交互的物品(例如:您碰到就消失的子弹或道具拾取,或者您一碰到就立即死亡的东西)。 - Merlyn Morgan-Graham
感谢您提供的答案。我想要实现的结果是比基于圆形和矩形盒子的碰撞更好。像素碰撞可能不够好,因为它们计算成本高昂。最近我读到了一些关于“凸形状”的内容,我可能会使用它们来增强我的碰撞系统行为。 - Eric
1
有关每像素的警告主要是因为我尝试了它,为一个老式平台游戏实现了一个“躲避”功能,并发现它感觉不对。使用正确的技术可以大大减少计算复杂度(最初只进行AABB碰撞,可能通过空间分区信息如网格系统或动态四叉树来减少,然后使用特殊的黑白碰撞掩码,并仅测试重叠部分)。凸形状绝对是一个好方法,可以让你在只有2D交互的游戏中替换3D艺术品。 - Merlyn Morgan-Graham
1个回答

0

你好,

首先请注意,你的代码中存在一个错误。你不能使用Matrix.multiplyMV()函数时源向量和目标向量相同(该函数将正确计算x坐标并覆盖源向量中的值。但是,它需要原始的x来计算y、z和w坐标,这些坐标也会出现问题)。此外,请注意,在第一步检测碰撞时,使用边界球可能更容易,因为它们不需要执行如此复杂的矩阵变换。

然后是碰撞检测。你不应该从位图或纹理中读取数据。你应该为你的对象构建轮廓线(这很容易,轮廓线只是一个位置列表)。之后,你需要构建填充轮廓线的凸多面体。可以通过例如耳剪辑算法实现。它可能不是最快的,但非常容易实现,并且只需执行一次。一旦你有了凸多面体,就可以使用矩阵变换它们的坐标,并检测与你的世界的碰撞(有许多关于射线-三角形相交的好文章可供参考),你将获得与基于像素的碰撞检测相同的精度。

希望对你有所帮助...


哦,我得检查一下其他的multiplyMV调用,感谢你指出来。不过有趣的是,由于错误使用multiplyMV,应用程序行为从未出现任何故障... 至于凸形状,我需要更深入地了解这个主题。非常感谢! - Eric

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接