2013-06-30 11 views
1

Я пытаюсь реализовать сбор с raycasting в OpenGL ES 2.0 для iPad-приложения. В частности, я хочу знать, какая ячейка карты, похожая на minecraft, состоит из квадратных ячеек с разной высотой, на которую пользователь нажал. Однако мой код не находит пересечения с любой ячейкой.Где я ошибался, пытаясь реализовать сбор с raycasting в OpenGL ES 2.0 для iOS?

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

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

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

Тогда я перевернуть ось х, потому что мое приложение находится в ландшафтном режиме и OPENGL Coords начать в другом углу, чем окно координаты

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

и выполнить unprojection с GLKitMathUnproject при г = 0 и г = 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; 
} 

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

ответ

0

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