Отпроектирование точки экрана на горизонтальную плоскость в ARKit - PullRequest
0 голосов
/ 23 сентября 2018

Я пытаюсь отменить проекцию некоторой точки на экране на координату на ARPlaneAnchor в мировом пространстве, используя ARKit.По сути, я хочу нарисовать маркер на плоскости земли в зависимости от того, куда указывает моя камера.ARKit предоставляет некоторые методы для этого, однако они прикреплены к классу ARCamera, и, к сожалению, в моем сценарии у меня есть доступ только к матрицам проекции, просмотра и преобразования камеры, и я не имею никакой ссылки на сами объекты ARFrame или ARCamera.Я написал нечто подобное (насколько я могу судить) для gluUnproject ().

func screenToWorld(screenPoint: CGPoint, depth: Float, screenSize: CGSize, projectionMatrix: simd_float4x4, viewMatrix:simd_float4x4) -> float3{

    let viewProj = viewMatrix * projectionMatrix
    let inverse = simd_inverse(viewProj)

    let x = (2.0 * screenPoint.x ) / screenSize.width - 1.0
    let y = (2.0 * screenPoint.y) / screenSize.height - 1.0

    let inPoint = float4(Float(x), Float(y), depth * 2.0 - 1.0, 1.0)

    var position = inPoint * inverse
    position.w = 1.0 / position.w

    position.x *= position.w
    position.y *= position.w
    position.z *= position.w

    return float3(position.x, position.y, position.z)
}


let pos = screenToWorld(screenPoint: CGPoint(360, 640), depth: depthBufferValue, screenSize: CGSize(720, 1280), projectionMatrix: projectionMatrix, viewMatrix: viewMatrix)
  1. screenPoint - это некоторая координата окна
  2. глубина рассчитывается путем считывания значения из буфера глубины в предыдущем проходе
  3. screenSize - размерviewport
  4. projectionMatrix приходит от projectionMatrix(for:.portrait, viewportSize: CGSize(720,1280),zNear: 0.001, zFar: 1000)
  5. viewMatrix приходит от viewMatrix(for:.portrait)

ЕдинственныйЯ не совсем уверен, является ли свойство viewMatrix.Единственное, о чем я мог подумать, это матрица преобразования, прикрепленная к камере.Тем не менее, я попробовал это, и это также, кажется, не дает мне правильную позицию.В gluUnproject они называют это значение матрицей modelView, в glm это просто называется model, поэтому меня немного смущает, что это должно быть.

Значение, полученное из функции unProject, которую я перевожуматрица тождественности вот так

var modelMatrix = matrix_identity_float4x4
modelMatrix = modelMatrix.translatedBy(x: pos.x, y: pos.y, z: pos.z)

И затем значения отправляются шейдеру вот так ...

encoder.setVertexBytes(&projectionMatrix, length: MemoryLayout<simd_float4x4>.stride, index: 1)
encoder.setVertexBytes(&viewMatrix, length: MemoryLayout<simd_float4x4>.stride, index: 2)
encoder.setVertexBytes(&modelMatrix, length: MemoryLayout<simd_float4x4>.stride, index: 3) 

Внутри моего вершинного шейдера я делаю

VertexOut vertexOut;
float4x4 modelViewMatrix = viewMatrix * modelMatrix;
vertexOut.position = projectionMatrix * modelViewMatrix * vertexIn.position;
return vertexOut;

Я думаю, что мое значение z правильное (значение глубины из буфера глубины), так что на самом деле мне просто нужно найти мои x и y.Я также не уверен на 100%, что делать со значением, возвращенным моей непроектированной функцией.Я предполагаю, что это всего лишь мировая координата, но, возможно, ее нужно каким-то образом масштабировать?

Мне бы очень хотелось получить помощь в получении правильной координаты или, если есть какие-либо ошибки в приведенном выше, укажите их!

1 Ответ

0 голосов
/ 23 сентября 2018

Для любого, кто столкнется с этим в будущем, решением (как предложено @ rabbid76) было изменение порядка умножения моей матрицы проекции и вида, а также моей обратной матрицы и inPoint.Мне также нужно было перевернуть координату y экрана, который я хотел проверить.

Вот полная функция:

func screenToWorld(screenPoint: CGPoint, depth: Float, screenSize: CGSize, projectionMatrix: simd_float4x4, viewMatrix:simd_float4x4) -> float3{

    let viewProj = projectionMatrix * viewMatrix
    let inverse = simd_inverse(viewProj)

    let x = (2.0 * screenPoint.x ) / screenSize.width - 1.0
    let y = 1.0 - (2.0 * screenPoint.y) / screenSize.height 

    let inPoint = float4(Float(x), Float(y), depth * 2.0 - 1.0, 1.0)

    var position = inverse * inPoint
    position.w = 1.0 / position.w

    position.x *= position.w
    position.y *= position.w
    position.z *= position.w

    return float3(position.x, position.y, position.z)
}
...