ARKit - Как получить расстояние по оси Z от текущего положения камеры - PullRequest
2 голосов
/ 29 мая 2020

У меня есть ARSCNView, который позволяет пользователям рисовать в трехмерном пространстве. Рисунок выглядит хорошо, если мы посмотрим на него под углом камеры, где мы его нарисовали, как на изображении 1 . Но когда я смотрю на него под другим углом, он выглядит не по форме, как на изображении 2 . Конечно, пользователи ожидают, что кольцо не изменит форму, если они посмотрят на него под другим углом.

Следующий код:

  1. Получение точки касания в 2d с помощью распознаватель жестов
  2. Нахождение соответствующей 3D-точки с помощью метода hitTest на sceneView
  3. Запрос на построение линии от предыдущей точки до текущей точки.

Код

@objc func panGesture(_ gestureRecognizer: UIPanGestureRecognizer) {

    gestureRecognizer.minimumNumberOfTouches = 1

    let results = self.sceneView.hitTest(gestureRecognizer.location(in: gestureRecognizer.view), types: ARHitTestResult.ResultType.featurePoint)
    guard let result = results.first else {
      return
    }

    if gestureRecognizer.state == .began {
      vector1 = SCNVector3Make(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z)
    } else if gestureRecognizer.state == .changed {
      let vector2 = SCNVector3Make(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z)

      guard let vector1 = vector1 else {
        self.vector1 = vector2
        return
      }

      let line = lineFrom(vector: vector1, toVector: vector2)
      let lineNode = SCNNode(geometry: line)
      sceneView.scene.rootNode.addChildNode(lineNode)

      self.vector1 = vector2
    } else if gestureRecognizer.state == .ended {
      vector1 = nil
    }
  }

Думаю, мне нужно нормализовать горизонтальное расстояние от текущего положения устройства до каждой точки на чертеже. Я попытался сделать это, изменив эту строку:

let vector2 = SCNVector3Make(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z)

на:

let vector2 = SCNVector3Make(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, vector1.z - currentCameraPositionRelativeToOrigin.z - currentCameraRotation.z)

Но это только усугубило проблему. Я был бы признателен за любые указатели в правильном направлении.

Изменить: вот код, который отображает aws фактические сегменты линии:

class func lineThrough(points: [SCNVector3], width:Int = 20, closed: Bool = false,  color: CGColor = UIColor.black.cgColor, mitter: Bool = false) -> SCNGeometry {

    // Becouse we cannot use geometry shaders in metal, every point on the line has to be changed into 4 verticles
    let vertices: [SCNVector3] = points.flatMap { p in [p, p, p, p] }

    // Create Geometry Source object
    let source = SCNGeometrySource(vertices: vertices)

    // Create Geometry Element object
    var indices = Array((0..<Int32(vertices.count)))
    if (closed) {
        indices += [0, 1]
    }
    let element = SCNGeometryElement(indices: indices, primitiveType: .triangleStrip)

    // Prepare data for vertex shader
    // Format is line width, number of points, should mitter be included, should line create closed loop
    let lineData: [Int32] = [Int32(width), Int32(points.count), Int32(mitter ? 1 : 0), Int32(closed ? 1 : 0)]

    let geometry = SCNGeometry(sources: [source], elements: [element])
    geometry.setValue(Data(bytes: lineData, count: MemoryLayout<Int32>.size*lineData.count), forKeyPath: "lineData")

    // map verticles into float3
    let floatPoints = vertices.map { float3($0) }
    geometry.setValue(NSData(bytes: floatPoints, length: MemoryLayout<float3>.size * floatPoints.count), forKeyPath: "vertices")

    // map color into float
    let colorFloat = color.components!.map { Float($0) }
    geometry.setValue(NSData(bytes: colorFloat, length: MemoryLayout<simd_float1>.size * color.numberOfComponents), forKey: "color")

    // Set the shader program
    let program = SCNProgram()
    program.fragmentFunctionName = "thickLinesFragment"
    program.vertexFunctionName = "thickLinesVertex"
    geometry.program = program

    return geometry
}
...