Search code examples
swiftscenekitaugmented-realityarkit3d-model

Loading huge animated 3D model in SceneKit causes memory issues


I have a problem with ARKit. My 3D model is 197MB in DAE format (without 20MB of textures). When I try to load my model in SceneKit without textures everything is fine but when I load it with textures my app has memory issues. My textures files are between 100kB and 4MB. When loaded with textures my app uses 1.84 GB RAM on my phone (iPhone X) and it causes memory issues. I have been searching on the internet but I could not find any solutions. Can somebody offer me help or some advice?

My code:

self.shipNode = SCNNode(daePath: "art.scnassets/s.scn")!

extension SCNNode {

    convenience init?(daePath: String) {

        self.init()

        guard let scene = SCNScene(named: daePath) else {
            return
        }

        DispatchQueue.main.async { [weak self] in
            for childNode in scene.rootNode.childNodes {
                self!.addChildNode(childNode)
            }
        }
    }
}

How I am using it:

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

    DispatchQueue.global().async { [weak self] in

        if let imageAnchor = anchor as? ARImageAnchor {
            let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width,
                                height: imageAnchor.referenceImage.physicalSize.height)

            plane.firstMaterial?.diffuse.contents = UIColor(white: 1, alpha: 0.8)
            self?.planeNode = SCNNode(geometry: plane)
            self?.planeNode.eulerAngles.x = -.pi / 2

            self?.shipNode.position = SCNVector3Zero
            self?.shipNode.position.z = 0.05

            DispatchQueue.main.async { [weak self] in

                self?.planeNode.addChildNode(self!.shipNode)

                self!.node.addChildNode(self!.planeNode)
            }
        }
    }
    return node
}

Solution

  • High-poly models with huge texture maps are not suitable for robust AR experience. Augmented Reality frameworks (such as ARKit or ARCore) are very processor-intensive, so there's no need to additionally increase a burden on CPU, GPU and memory.

    Why ARKit apps are so CPU-intensive?

    Your ARKit app uses 4 sensors to track a surrounding environment at 60 fps, and it simultaneously renders (with a help of SceneKit or RealityKit) your animated 3D model with all the textures, lights and shadows, and, after that, it composites in real-time a 2D render of your model (in RGBAZ pattern) over high-res RGB video from rear camera. That's too much for your device, isn't it?

    Hence, any high-poly models with huge textures not only cause a memory and CPU/GPU issues, but also very quickly drain your battery. And, please take into consideration - iPhone X has only 3 GB of RAM of which iOS uses more than 1 GB, so memory issues are quite possible in your particular case.

    So, my recommendations for creating a 3D model for robust AR experience are the following:

    • Low-poly geometry (usually 10,000 polygons per model are fine)
    • UV-mapped Texture resolution – not more than 1024 x 1024 pix
    • Preferably, pre-baked UV-mapped shadows for static elements
    • Use of JPEG format with 0% compression for texture (PNG is larger)
    • Don't use too many PBR shaders (with metalness property) in your scene