RealityKit - MeshAnchor with Custom Material problems

trying to put custom material on ARMeshAnchor, but during the session the FPS frequency begins to decrease, and the following warning comes out

Link to the video example of braking FPS

https://www.dropbox.com/s/p7g7qgvb5o95gdf/RPReplay_Final1637641112.mov?dl=0

Console Warning

ARSessionDelegate is retaining 11 ARFrames. This can lead to future camera frames being dropped

CameraViewController

final class CameraViewController: UIViewController {

    private let arView = ARView().do {
        $0.automaticallyConfigureSession = false
    }

    private var meshAnchorTracker: MeshAnchorTracker?

    override func viewDidLoad() {
        super.viewDidLoad()
        MetalLibLoader.initializeMetal()
        setupSubviews()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        setupARSession()
    }

    private func setupSubviews() {
        view.addSubview(arView)
        arView.frame = view.bounds
    }

    private func setupARSession() {
        configureWorldTracking()
        setupPhysicsOrigin()
    }

    private func configureWorldTracking() {
        let configuration = ARWorldTrackingConfiguration()

  let sceneReconstruction: ARWorldTrackingConfiguration.SceneReconstruction = .mesh
        if ARWorldTrackingConfiguration.supportsSceneReconstruction(sceneReconstruction) {
            configuration.sceneReconstruction = sceneReconstruction
            meshAnchorTracker = .init(arView: arView)
        }

        configuration.planeDetection = .horizontal
        arView.session.run(configuration, options: [.resetSceneReconstruction])
        arView.renderOptions.insert(.disableMotionBlur)
        arView.session.delegate = self
    }

    private func setupPhysicsOrigin() {
        let physicsOrigin = Entity()
        physicsOrigin.scale = .init(repeating: 0.1)
        let anchor = AnchorEntity(world: SIMD3<Float>())
        anchor.addChild(physicsOrigin)
        arView.scene.addAnchor(anchor)
        arView.physicsOrigin = physicsOrigin
    }

    func updateAnchors(anchors: [ARAnchor]) {
        for anchor in anchors.compactMap({ $0 as? ARMeshAnchor }) {
            meshAnchorTracker?.update(anchor)
        }
    }
}

extension CameraViewController: ARSessionDelegate {
    func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
        updateAnchors(anchors: anchors)
    }

    func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) {
        updateAnchors(anchors: anchors)
    }

    func session(_ session: ARSession, didRemove anchors: [ARAnchor]) {
        for anchor in anchors.compactMap({ $0 as? ARMeshAnchor }) {
            meshAnchorTracker?.remove(anchor)
        }
    }
}

MeshAnchorTracker

struct MeshAnchorTracker {
    var entries: [ARMeshAnchor: Entry] = [:]
    weak var arView: ARView?

    init(arView: ARView) {
        self.arView = arView
    }

    class Entry {
        var entity: AnchorEntity
        private var currentTask: Cancellable?

        var nextTask: LoadRequest<MeshResource>? {
            didSet {
                scheduleNextTask()
            }
        }

        static let material: RealityKit.CustomMaterial = {
            let customMaterial: CustomMaterial
            let surfaceShader = CustomMaterial.SurfaceShader(named: "plasma", in: MetalLibLoader.library)
            do {
                try customMaterial = CustomMaterial(surfaceShader: surfaceShader, lightingModel: .lit)
            } catch {
                fatalError(error.localizedDescription)
            }
            return customMaterial
        }()

        func scheduleNextTask() {
            guard let task = nextTask else { return }
            guard currentTask == nil else { return }
            self.nextTask = nil
            currentTask = task
                .sink(
                    receiveCompletion: { result in
                        switch result {
                        case .failure(let error): assertionFailure("\(error)")
                        default: return
                        }
                    },
                    receiveValue: { [weak self] mesh in
                        self?.currentTask = nil
                        self?.entity.components[ModelComponent.self] = ModelComponent(
                            mesh: mesh,
                            materials: [Self.material]
                        )
                        self?.scheduleNextTask()
                    }
                )
        }
        init(entity: AnchorEntity) {
            self.entity = entity
        }
    }

    mutating func update(_ anchor: ARMeshAnchor) {
        let tracker: Entry = {
            if let tracker = entries[anchor] { return tracker }
            let entity = AnchorEntity(world: SIMD3<Float>())
            let tracker = Entry(entity: entity)
            entries[anchor] = tracker
            arView?.scene.addAnchor(entity)
            return tracker
        }()

        let entity = tracker.entity
        do {
            entity.transform = .init(matrix: anchor.transform)
            let geom = anchor.geometry
            var desc = MeshDescriptor()
            let posValues = geom.vertices.asSIMD3(ofType: Float.self)
            desc.positions = .init(posValues)
            let normalValues = geom.normals.asSIMD3(ofType: Float.self)
            desc.normals = .init(normalValues)
            do {
                desc.primitives = .polygons(
                    (0..<geom.faces.count).map { _ in UInt8(geom.faces.indexCountPerPrimitive) },
                    (0..<geom.faces.count * geom.faces.indexCountPerPrimitive).map {
                        geom.faces.buffer.contents()
                            .advanced(by: $0 * geom.faces.bytesPerIndex)
                            .assumingMemoryBound(to: UInt32.self).pointee
                    }
                )
            }
            tracker.nextTask = MeshResource.generateAsync(from: [desc])
        }
    }

    mutating func remove(_ anchor: ARMeshAnchor) {
        if let entity = self.entries[anchor] {
            entity.entity.removeFromParent()
            self.entries[anchor] = nil
        }
    }
}

extension ARGeometrySource {
    func asArray<T>(ofType: T.Type) -> [T] {
        dispatchPrecondition(condition: .onQueue(.main))
        assert(MemoryLayout<T>.stride == stride, "Invalid stride \(MemoryLayout<T>.stride); expected \(stride)")
        return (0..<self.count).map {
            buffer.contents().advanced(by: offset + stride * Int($0)).assumingMemoryBound(to: T.self).pointee
        }
    }

    func asSIMD3<T>(ofType: T.Type) -> [SIMD3<T>] {
        return asArray(ofType: (T, T, T).self).map { .init($0.0, $0.1, $0.2) }
    }
}

What could the problem? 🥵

Hi, does the FPS start out around 60, and decrease with time? That is likely due to the CPU heating up, which causes the frame rate to drop.

RealityKit - MeshAnchor with Custom Material problems
 
 
Q