Выровнять трехмерный объект параллельно вертикальной плоскости, обнаруженной estametedVerticalPlane - PullRequest
0 голосов
/ 21 мая 2019

У меня есть эта книга, но я сейчас делаю ремикс приложения для мебели из видеоурока, который был бесплатным на неделе AR / VR.

Я бы хотел, чтобы 3D-холст был выровнен по стене / вертикальной плоскости.

Это оказывается сложнее, чем я думал. Позиционирование не является проблемой. Так же, как и в приложении для расстановки мебели, вы можете просто получить column3 в hittest.worldtransform и указать новую геометрию для вектора vector3.

Но я не знаю, что мне нужно сделать, чтобы мой 3D-объект повернулся лицом вперед на выровненной обнаруженной плоскости. Поскольку у меня есть объект холста, фотография находится на одной стороне холста. При размещении фотография ВСЕГДА обращена в сторону.

Я думал о применении произвольного поворота к холсту лицом вперед, но тогда это было правильно, только если я смотрю на север и кладу холст на стену справа от меня.

Я перепробовал довольно много решений, но одно всегда использует .existingPlaneUsingExtent. для обнаружения в вертикальной плоскости. Это позволяет вам получить ARPlaneAnchor от hittest.anchor? as ARPlaneAnchor. Если вы попробуете это при использовании .estimatedVerticalPlane the anchor? это nil

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

Моя текущая мысль состоит в том, чтобы получить передний вектор холста и повернуть его к переднему вектору вертикальной плоскости, обнаруженной UIImage или самой хитовой точке.

Как бы я получил прямой вектор из 3D-точки. ИЛИ получить фронтальный вектор из изображения сетки, то есть UIImage, который помещается как наложение, когда ARKit обнаруживает вертикальную стену?

Вот пример. Канва показывает заднюю часть холста и не параллельна обнаруженной вертикальной плоскости, которая является столбцом. Но есть сетка «Поместить плакат», с помощью которой я хочу, чтобы холст выровнялся, и я могу видеть фотографию.

canvasback

Вещи, которые я пробовал. используя .estimatedVerticalPlane Оценка ARKitВертикальное испытание на удар самолета получает вращение плоскости

Я не знаю, как правильно применить эту матрицу, а угол наклона получен из ответа SO.

моя функция добавления изображения.

func addPicture(hitTestResult: ARHitTestResult) {
    // I would like to convert estimate hitTest to a anchorpoint
    // it is easier to rotate a node to a anchorpoint over calculating eularAngles
    // we have all detected anchors in the _Renderer SCNNode. however there are

    // Get the current furniture item, correct its position if necessary,
    // and add it to the scene.
    let picture = pictureSettings.currentPicturePiece()

    //look for the vertical node geometry in verticalAnchors
    if let hitPlaneAnchor = hitTestResult.anchor as? ARPlaneAnchor {
      if let anchoredNode = verticalAnchors[hitPlaneAnchor]{
        //code removed as a .estimatedVerticalPlane hittestResult doesn't get here
      }
    }else{
      // Transform hitresult to world coords
      let worldTransform = hitTestResult.worldTransform
      let anchoredNodeOrientation = worldTransform.eulerAngles
        picture.rotation.y =
          -.pi * anchoredNodeOrientation.y
        //set the transform matirs
        let positionMatris = worldTransform.columns.3
        let position = SCNVector3 (
          positionMatris.x,
          positionMatris.y,
          positionMatris.z
        )
        picture.position = position + pictureSettings.currentPictureOffset();

    }
    //parented to rootNode of the scene
    sceneView.scene.rootNode.addChildNode(picture)
  }

Спасибо за любую доступную помощь.

Отредактировано: Я заметил, что «ручная работа» или 3D-модель неверна / противоположна? Положительный Z направлен влево, а положительный X направлен на камеру, так как я ожидаю, что это передняя часть модели. Это проблема?

1 Ответ

0 голосов
/ 23 мая 2019

Вам следует избегать добавления узла непосредственно в сцену, используя мировые координаты.Скорее вы должны уведомить ARSession об интересующей области, добавив ARAnchor, а затем использовать обратный вызов сеанса, чтобы продать SCNNode для добавленной привязки.

Например, ваш тест попадания может выглядеть примерно так:

@objc func tapped(_ sender: UITapGestureRecognizer) {
    let location = sender.location(in: sender.view)
    guard let hitTestResult = sceneView.hitTest(location, types: [.existingPlaneUsingGeometry, .estimatedVerticalPlane]).first,
          let planeAnchor = hitTestResult.anchor as? ARPlaneAnchor,
          planeAnchor.alignment == .vertical else { return }
    let anchor = ARAnchor(transform: hitTestResult.worldTransform)
    sceneView.session.add(anchor: anchor)
}

Здесь распознанный жест касания используется для обнаружения касаний в ARSCNView.При обнаружении касания выполняется тест на попадание в поисках существующих и предполагаемых плоскостей.Если плоскость вертикальная, мы добавляем ARAnchor, добавляемое worldTransform результата теста на попадание, и добавляем этот якорь к ARSession.Это будет регистрировать эту точку как область интереса для ARSession, поэтому мы получим лучшее отслеживание и меньший сдвиг после того, как наш контент будет добавлен туда.

Далее нам нужно продать наш SCNNode длянедавно добавленный ARAnchor.Например,

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
    if anchor is ARPlaneAnchor {
        let anchorNode = SCNNode()
        anchorNode.name = "anchor"
        return anchorNode
    } else {
        let plane = SCNPlane(width: 0.67, height: 1.0)
        plane.firstMaterial?.diffuse.contents = UIImage(named: "monaLisa")
        let planeNode = SCNNode(geometry: plane)
        planeNode.eulerAngles = SCNVector3(CGFloat.pi * -0.5, 0.0, 0.0)
        let node = SCNNode()
        node.addChildNode(planeNode)
        return node
    }
}

Здесь мы сначала проверяем, является ли якорь ARPlaneAnchor.Если это так, мы продаем пустой узел для целей отладки.Если это не так, то это якорь, который был добавлен в результате теста на попадание.Итак, мы создаем геометрию и узел для самого последнего касания.Поскольку это вертикальная плоскость и наш контент лежит ровно, нужно повернуть его вокруг оси х.Поэтому мы корректируем это eulerAngles, чтобы оно было в вертикальном положении.Если бы мы возвращали planeNode, то прямая корректировка eulerAngles была бы удалена, поэтому мы добавляем ее как дочерний узел пустого узла и возвращаем ее.

Должно привести к чему-то вроде следующего.

Screencast

...