1

我正在尝试为 iPad 应用程序在 OpenGL ES 2.0 中使用光线投射实现拾取。具体来说,我想知道用户点击了由高度不同的方形单元组成的类似我的世界地图的哪个单元。但是,我的代码没有找到与任何单元格的交集。

在我的手势识别器方法中,我首先获取点和视口尺寸

UITapGestureRecognizer* tapRecognizer = (UITapGestureRecognizer*) recognizer;
CGPoint tapLoc = [tapRecognizer locationInView: self.view];

GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);

然后我翻转 x 轴,因为我的应用程序处于横向模式,并且 openGL 坐标从与窗口坐标不同的角开始

tapLoc.x = viewport[2] -  tapLoc.x;

并使用 GLKitMathUnproject 对 z = 0 和 z = 1 值执行反投影,然后将结果向量传递给函数,该函数将返回用户点击的单元格的坐标作为结构 BPPoint(只有两个整数,x 和 y)。该地图目前没有任何变换,所以我假设我应该使用单位矩阵进行变换,并且投影矩阵是使用 glkmatrix4makeperspective 制作的。

GLKVector3 nearPt = GLKMathUnproject(GLKVector3Make(tapLoc.x, tapLoc.y, 0.0), GLKMatrix4Identity, [BPGlobalEnv globalVars].cameraMatrix, &viewport[0] , &testResult);

GLKVector3 farPt = GLKMathUnproject(GLKVector3Make(tapLoc.x, tapLoc.y, 1.0), GLKMatrix4Identity, [BPGlobalEnv globalVars].cameraMatrix, &viewport[0] , &testResult);

BPPoint destination = [gameEngine.currMap gridForPoint: farPt fromPoint: nearPt];

这是该方法的主体。我基本上只是循环并重新生成地图每个正方形顶部的几何图形(效率低,我知道),方法与我用来将几何图形传递到 VBO 以首先绘制它的方法相同。

-(BPPoint) gridForPoint: (GLKVector3) ray fromPoint: (GLKVector3) cameraCoords

{
size_t i = 0;
size_t j;

GLfloat* buffer = malloc(sizeof(GLfloat) * squareSize);

for (NSArray* row in self.mapCells) {

    j = 0;

    for (BPGridCell* cell in row) {

        GLfloat a[3];
        a[0] = i * tileSize;
        a[1] = cell.height * step;
        a[2] = j * tileSize;
        GLfloat b[3];
        b[0] = (i + 1) * tileSize;
        b[1] = cell.height * step;
        b[2] = (j + 1) * tileSize;

        [self squareForPoint:a point:b pointer: buffer];

        GLKVector3 v1 = GLKVector3Make(buffer[0], buffer[1], buffer[2]);
        GLKVector3 v2 = GLKVector3Make(buffer[3], buffer[4], buffer[5]);
        GLKVector3 v3 = GLKVector3Make(buffer[6], buffer[7], buffer[8]);
        GLKVector3 v21 = GLKVector3Make(buffer[9], buffer[10], buffer[11]);
        GLKVector3 v22 = GLKVector3Make(buffer[12], buffer[13], buffer[14]);
        GLKVector3 v23 = GLKVector3Make(buffer[15], buffer[16], buffer[17]);

        if ([self ray: ray fromCamera: cameraCoords intersectsTriangleWithV1: v1 V2: v2 V3: v3] ||
            [self ray: ray fromCamera: cameraCoords intersectsTriangleWithV1: v21 V2: v22 V3: v23]) {

            NSLog(@"found intersection");
            free(buffer);
            BPPoint toReturn;
            toReturn.x = i;
            toReturn.y = j;
            NSLog(@"%ld, %ld", i, j);
            return toReturn;
        }

        j += 1;
    }

    i += 1;
}

free(buffer);
BPPoint toReturn;
toReturn.x = i;
toReturn.y = j;
NSLog(@"%ld, %ld", i, j);
return toReturn;
}

以及用于测试相交三角形的代码,我从这里转换为 objc ( http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/Fast%20MinimumStorage%20RayTriangle%20Intersection .pdf)如下:

-(BOOL) ray: (GLKVector3) ray fromCamera: (GLKVector3) camera intersectsTriangleWithV1: (GLKVector3) v1 V2: (GLKVector3) v2 V3: (GLKVector3) v3
{

GLKVector3 e1 = GLKVector3Subtract(v2, v1);
GLKVector3 e2 = GLKVector3Subtract(v3, v1);

GLKVector3 h = GLKVector3CrossProduct(ray, e2);

float det = GLKVector3DotProduct(e1, h);

if (det > -0.00001 && det < 0.00001) {

    return NO;
}

float invDet = 1.0/det;
GLKVector3 s = GLKVector3Subtract(camera, v1);

float u =  GLKVector3DotProduct(s, h) * invDet;

if (u < 0.0 || u > 1.0) {

    return NO;
}

GLKVector3 q = GLKVector3CrossProduct(s, e1);

float v = invDet * GLKVector3DotProduct(ray, q);

if (v < 0.0 || u + v > 1.0) {

    return NO;
}

    return YES;
}

当我使用 10x10 地图运行它时,它通常会为坐标打印 10,10 而不会找到交叉点。我在哪里搞砸了概念或实施这个或两者兼而有之?

4

1 回答 1

0

我找到了解决方案: glgetintegerv 调用返回翻转值,大概是因为设备处于横向模式。我还必须从远点中减去近点,以获得正确的射线方向矢量。

于 2013-07-01T22:58:46.060 回答