Объект одного размера всегда оказывается застрявшим перед камерой - PullRequest
1 голос
/ 31 марта 2020

Я создал небольшое демонстрационное приложение дополненной реальности, в котором я хотел разместить большой объект в AR. Но он всегда кажется застрявшим перед камерой, когда объект масштабируется до 1,0, и я не могу видеть объект со всех сторон. Где, как будто я масштабировал его до 0,001, я могу видеть весь объект со всех сторон. Может кто-нибудь объяснить, почему я сталкиваюсь с такой проблемой с большими моделями и есть ли способ решить эту проблему.

Размеры модели: -

enter image description here

import UIKit
import ARKit
import SceneKit

class ViewController: UIViewController {

    @IBOutlet weak var sceneView: ARSCNView!
    private let configuration = ARWorldTrackingConfiguration()
    private var node: SCNNode!

    //MARK: - Life cycle
    override func viewDidLoad() {
        super.viewDidLoad()

        self.sceneView.showsStatistics = false
        self.sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints]
        self.sceneView.automaticallyUpdatesLighting = false
        self.sceneView.delegate = self
        self.addTapGesture()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

       configuration.planeDetection = .horizontal
       self.sceneView.session.run(configuration)

    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.sceneView.session.pause()
    }

    //MARK: - Methods

    func addObject(hitTestResult: ARHitTestResult) {

        let scene = SCNScene(named: "art.scnassets/Cube.obj")!
        let modelNode = scene.rootNode.childNodes.first
        modelNode?.position = SCNVector3(hitTestResult.worldTransform.columns.1.x,
                                         hitTestResult.worldTransform.columns.2.y,
                                         -800)
        let scale = 1
        modelNode?.scale = SCNVector3(scale, scale, scale)
        self.node = modelNode
        self.sceneView.scene.rootNode.addChildNode(modelNode!)


       let lightNode = SCNNode()
       lightNode.light = SCNLight()
       lightNode.light?.type = .omni
       lightNode.position = SCNVector3(x: 0, y: 10, z: 20)
       self.sceneView.scene.rootNode.addChildNode(lightNode)

       let ambientLightNode = SCNNode()
       ambientLightNode.light = SCNLight()
       ambientLightNode.light?.type = .ambient
       ambientLightNode.light?.color = UIColor.darkGray
       self.sceneView.scene.rootNode.addChildNode(ambientLightNode)


    }

    private func addTapGesture() {
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap(_:)))
        self.sceneView.addGestureRecognizer(tapGesture)
    }

    @objc func didTap(_ gesture: UIPanGestureRecognizer) {
        let tapLocation = gesture.location(in: self.sceneView)
        let results = self.sceneView.hitTest(tapLocation, types: .featurePoint)

        guard let result = results.first else {
            return
        }

        let translation = result.worldTransform.translation

        guard let node = self.node else {
            self.addObject(hitTestResult: result)
            return
        }
        node.position = SCNVector3Make(translation.x, translation.y, translation.z)
        self.sceneView.scene.rootNode.addChildNode(self.node)
    }

}

extension float4x4 {
    var translation: SIMD3<Float> {
        let translation = self.columns.3
        return SIMD3<Float>(translation.x, translation.y, translation.z)
    }
}

Также, пожалуйста, смотрите прикрепленную ссылку на видеоролики: -

  1. Захват видео после масштабирования модели до 0,001 https://drive.google.com/open?id=1sBFEyleSIBMmQV5MgA6rOqJZEc0YUyKR

  2. Захват видео после масштабирования модели до 1 https://drive.google.com/open?id=1k5-adqLCcwaXoYY1ZePE2D-mOdyLvHvi

В масштабе 1 я не могу видеть весь объект со всех сторон, и объект также перемещается с помощью камеры iPad. Есть ли способ разместить объект в фиксированном месте?

Заранее спасибо.

1 Ответ

0 голосов
/ 01 апреля 2020

Обновлено

Я проверял это. Ваша модель имеет неправильный начальный масштаб. Это в метрах!

  • Width = 786 метров
  • Height = 676 метров
  • Depth = 456 метров

Используйте следующие значения, чтобы уменьшить модель:

let scene = SCNScene(named: "art.scnassets/Cube.scn")!

let modelNode: SCNNode? = scene.rootNode.childNode(withName: "_material_1", 
                                                recursively: true)

let scale: Float = 0.002           // 500 times smaller

modelNode?.scale = SCNVector3(scale, scale, scale)

... и вернуть вашу модель вдоль оси Z:

modelNode?.position.z = 0

Вот почему ваша модель застревает впереди. камеры - это связано с тем, что вы поместили модель в 800 метрах от начала координат. Таким образом, вы не могли смотреть на него при правильном параллаксе.


Попробуйте следующий код, чтобы разместить вашу модель в ожидаемой позиции теста удара:

@objc func tap(gesture: UITapGestureRecognizer) {

    let touch: CGPoint = gesture.location(in: sceneView)

    let result: [ARHitTestResult] = sceneView.hitTest(touch, 
                                               types: .existingPlaneUsingExtent)

    guard let hitTest: ARHitTestResult = result.first 
    else { return }

    self.loadModel(hitTest)
}

Затем создайте содержимое для метода loadModel(:_):

func loadModel(_ result: ARHitTestResult) {

    let scene = SCNScene(named: "art.scnassets/myScene.scn")!

    let node: SCNNode? = scene.rootNode.childNode(withName: "model", 
                                               recursively: true)

    node?.position = SCNVector3(result.worldTransform.columns.3.x,
                                result.worldTransform.columns.3.y,
                                result.worldTransform.columns.3.z)

    // Please consider that ARKit's and SceneKit's scenes are in Meters
    node?.scale = SCNVector3(0.5, 2.0, 0.5)

    self.sceneView.scene.rootNode.addChildNode(node!)
}

И затем введите #selector с помощью метода @ obj c tap:

override func viewDidLoad() {
    super.viewDidLoad()

    let gestureRecognizer = UITapGestureRecognizer(target: self, 
                                                   action: #selector(tap))

    self.sceneView.addGestureRecognizer(gestureRecognizer)
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    let config = ARWorldTrackingConfiguration()
    config.planeDetection = .horizontal
    self.sceneView.session.run(config)
}

И мне кажется, что вы используете неправильное преобразование, потому что оно находится в последнем столбце матрицы преобразования 4x4:

  ┌               ┐
  |  1  0  0  tx  |
  |  0  1  0  ty  |
  |  0  0  1  tz  |
  |  0  0  0  1   |
  └               ┘
  • 1. проверьте, где находится точка вращения вашей 3D-модели? Если точка вращения вашей модели смещена по осям + Z, то она всегда стоит перед вашей камерой .

  • 2. Убедитесь, что масштаб вашей модели не в десятках или сотнях метров .


Решение для шкалы:

Если Вы хотите, чтобы узел с масштабом по умолчанию (1,0) поместил ваш modelNode с scale=0.002 в родительский узел с scale=1.0:

let scene = SCNScene(named: "art.scnassets/Cube.scn")!

let modelNode: SCNNode? = scene.rootNode.childNode(withName: "_material_1", 
                                                recursively: true)

let scale: Float = 0.002           // 500 times smaller

modelNode?.scale = SCNVector3(scale, scale, scale)

let defaultScaleNode = SCNNode()
defaultScaleNode.addChildNode(modelNode!)
defaultScaleNode.scale = SCNVector3(1.0, 1.0, 1.0)
...