ARKit + SceneKit добавляет физические тела, вызывающие массивные падения кадров - PullRequest
0 голосов
/ 16 января 2020

Я создал игру в SceneKit и в настоящее время портирую в проект ARKit. Все прошло гладко, пока физика точек не добавилась к узлам, которые необходимы для присоединения физического тела. FPS идет от стабильного 60FPS до добавления физических тел примерно до 5FPS после добавления физических тел. В данный момент я застрял на этом и попробовал множество вещей, чтобы решить эту проблему, но безуспешно. Кто-нибудь знает, что может вызвать это?

ПРИМЕЧАНИЕ Этот же код прекрасно работает только в обычном проекте SceneKit.

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

       let configuration = ARImageTrackingConfiguration()

       guard let trackingImages = ARReferenceImage.referenceImages(inGroupNamed: "AR-Images", bundle: nil) else {
           fatalError("Couldn't load tracking images.")
       }

       configuration.trackingImages = trackingImages
       //gameView.debugOptions = [.showPhysicsShapes]
       gameView.session.run(configuration)

Приведенный ниже метод является частью ARSCNViewDelegate и создает опорную точку, в которую будет загружаться и привязываться мир.

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {

            guard let imageAnchor = anchor as? ARImageAnchor else { return nil }

            // create a plane at the exact physical width and height of our reference image
            let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width, height: imageAnchor.referenceImage.physicalSize.height)

            // make the plane have a transparent blue color
            plane.firstMaterial?.diffuse.contents = UIColor.blue.withAlphaComponent(0.5)

            // wrap the plane in a node and rotate it so it's facing us
            let planeNode = SCNNode(geometry: plane)
            planeNode.eulerAngles.x = -.pi / 2

            // now wrap that in another node and send it back
            let node = SCNNode()
            node.name = "holderNode"
            planeNode.name = "plane"
            node.addChildNode(planeNode)

            DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
                self.setup(node: planeNode)
            }

         return node
    }

Это Метод настройки, используемый для инициализации игры и ее зависимостей.

    func setup(node: SCNNode){
        let gameScale:Float = 0.05
        let configuration = ARWorldTrackingConfiguration()
        gameView.session.run(configuration)

        setupScene(node: node, scale: gameScale)
        setupPlayer(scale: gameScale)
        setupGameManager()
        setupCamera()
        setupNPCS()
        setupDPad()

        // setup collisions
        setupCollisions(scale: gameScale)
        world.addChildNode(playerNode)

        // connect to multiplayer server
        NetworkController.shared.connectToServer()

        // Add tap gesture
        let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(_:)))
        gameView.addGestureRecognizer(tap)
        gameState = .playing

        // Add views
        gameView.addSubview(gameManager.topMenu)
        gameView.addSubview(gameManager.actionButtonView)
    }

Этот метод используется для настройки сцены.

   private func setupScene(node: SCNNode, scale: Float){
        gameView.allowsCameraControl = false
        gameView.antialiasingMode = .none
        guard let worldScene = SCNScene(named:"art.scnassets/Scene/world.scn") else { return }
        world = worldScene.rootNode.childNode(withName: "world", recursively: true)
        gameView.scene.physicsWorld.contactDelegate = self
        world.rotation = SCNVector4(x: 1,
                                    y: 0,
                                    z: 0,
                                    w: Float.pi / 2)
        world.position.z = -5
        node.addChildNode(self.world)
        node.scale = SCNVector3(x: scale, y: scale, z: scale)
    }

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

let root должен получить root, в котором объекты находятся в сцене ARSCNView.

    private func setupCollisionBitMasks(nodeName: String, withChildNodes: Bool, scale: Float){
        var collisionNodes = [SCNNode]()
        guard let root = self.gameView.scene.rootNode.childNode(withName: "plane", recursively: true) else { return }
        guard let nodes = root.childNode(withName: nodeName, recursively: true) else { return }

        for node in nodes.childNodes {
            if(withChildNodes){
                for node in node.childNodes {
                    collisionNodes.append(node)
                }
            }else{
                collisionNodes.append(node)
            }
        }

        for node in collisionNodes {
            node.physicsBody = SCNPhysicsBody.static()
            node.physicsBody!.categoryBitMask = BitMasks.BitmasksWall.rawValue
            node.physicsBody!.physicsShape = SCNPhysicsShape(node: node, options: [.type: SCNPhysicsShape.ShapeType.concavePolyhedron as NSString, SCNPhysicsShape.Option.scale: SCNVector3(scale, scale, scale)])
        }
    }
...