Где я ошибся, пытаясь реализовать комплектацию с помощью raycasting в OpenGL ES 2.0 для iOS?

Я пытаюсь реализовать комплектацию с помощью raycasting в OpenGL ES 2.0 для приложения для iPad. В частности, я хочу знать, какая ячейка карты, похожей на майнкрафт, состоит из квадратных ячеек с разной высотой, на которые нажал пользователь. Однако мой код не находит пересечения ни с одной ячейкой.

В моем методе распознавания жестов я сначала получаю размеры точки и области просмотра

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;

И выполните unprojection с GLKitMathUnproject для значений z = 0 и z = 1, затем передайте результирующие векторы в функцию, которая будет возвращать координаты ячейки, которую пользователь нажал в виде struct 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;
}

Когда я запускаю это с картой 10х10, она печатает 10,10 для координат, обычно не находя пересечения. Где я облажался концептуально или в реализации этого или обоих?

1 ответ

Я нашел решение: вызов glgetintegerv вернул перевернутые значения, предположительно потому, что устройство находилось в ландшафтном режиме. Мне также пришлось вычесть ближнюю точку из дальней, чтобы получить правильный вектор направления луча.

Другие вопросы по тегам