2
votes

There seems to be a delay for when my SCNView is ready, and when it actually renders on my view - I always see a split second of white before the view appears. What can I do to prevent this?

func loadModels(frame:CGRect, type:ItemViewType, completion: (() -> Void)!) {
    self.container = self.scene.rootNode.childNodeWithName("Container", recursively: true)!
    self.item = self.container.childNodeWithName("Item", recursively: true)
    self.pattern = self.item.childNodeWithName("TopLayer", recursively: true)
    self.buttom = self.item.childNodeWithName("BottomRubber", recursively: true)!
    self.shell = self.item.childNodeWithName("Shell", recursively: true)!

    self.leftRimLit = self.scene.rootNode.childNodeWithName("leftRimLit", recursively: true)
    self.specDirLit = self.scene.rootNode.childNodeWithName("specDirLit", recursively: true)
    self.omni = self.scene.rootNode.childNodeWithName("omni", recursively: true)

    self.scnView = SCNView(frame: frame)

    self.scnView!.scene = self.scene

    self.scnView!.autoenablesDefaultLighting = false

    //default position
    self.scnView?.pointOfView?.position = SCNVector3Make(-1.41011, -21.553, 3.34132)
    self.scnView?.pointOfView?.eulerAngles = SCNVector3Make(1.58788, -0.0114007, -0.0574705)
    self.scnView?.pointOfView?.scale = SCNVector3Make(1, 1, 1.5)

    self.item.pivot = SCNMatrix4MakeTranslation(0, 0, 4)
    self.item.position = SCNVector3(x: 0.387027979, y: 9.58867455, z: 3.71733069)
    self.item.scale = SCNVector3(x: 1.0999999, y: 1.0999999, z: 1.10000002)
    self.item.rotation = SCNVector4(x: 0.865282714, y: 0.455411941, z: 0.20948948, w: 2.20000005)

    self.container.pivot = SCNMatrix4MakeTranslation(0, 0, 0)

    self.setBackground(type)
    self.setItemPosition(type)

    completion()
}

All of the positioning a background is correct once it does finally appear.

    self.SO3DItemView = SO3DItemModel(frame: self.view.frame)
    self.SO3DItemView!.loadModels(self.view.frame, type: .Tada, completion:
        {() -> Void in
            self.view.insertSubview(self.SO3DItemView!.scnView!, belowSubview:self.overlay)

    UIView.animateWithDuration(0.7, delay: 0.0, options: .CurveEaseIn, animations:
                    {() -> Void in
                    self.overlay.alpha = 0.0
                    }, completion:{ (finished: Bool) -> Void in
                        self.view.sendSubviewToBack(self.overlay)
                })

Right now I have an overlay that fades out to mitigate some of this, but on slow devices (iPhone 5) I can still see the white before the scnView snaps in to complete.

1

1 Answers

4
votes

The SCNSceneRenderer protocol (your SCNView) has a function prepareObjects:withCompletionHandler: that will accept a SCNScene. This will instruct SceneKit to perform any initialisation needed, otherwise it will wait for the scene to be added before transferring data to the GPU, etc.

FWIW I've settled on using background threads to get around this same issue. Simple example below...

let scene = SCNScene()

let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {

    //lengthy scene setup process
    let slowNode = SCNNode(geometry:SCNSphere(radius:1.0))
    sleep(2)

    dispatch_async(dispatch_get_main_queue()) 
    {
        scene.rootNode.addChildNode(slowNode)
    }
}

let quickNode = SCNNode(geometry:SCNBox(width:1.0, height:1.0, length:1.0))
scene.rootNode.addChildNode(quickNode)

scnView.scene = scene

If you were to run this code, which I haven't, you should see the box appear immediately when the app launches. Two seconds later the sphere will be added to the scene.