Sirop4ik
Sirop4ik

Reputation: 5263

SceneKit – Why SCNLight created automatically in SCNScene?

It is a kind of weird phenomena that I found out. There is a very simple example, I have an ARSCNView which is empty, just rootnode and camera, so it means that the camera is open, but there is nothing on the screen (just camera).

There is a method that I call from the viewDidLoad() { printAllScene(node: scnView.scene.rootNode) } in order to print all the nodes on the scene

    private func printAllScene(node: SCNNode) {
        print("node: \(node), parent is: \(String(describing: node.parent))")
        
        for curNode in node.childNodes {
            printAllScene(node: curNode)
        }
    }

This recursive method prints all the nodes on the scene, so after I call it in the viewDidLoad() I get such an output

>>> 1
node: <SCNNode: 0x283313300 | 1 child>, parent is: nil
node: <SCNNode: 0x283318500 | camera=<SCNCamera: 0x1065261c0> | no child>, parent is: Optional(<SCNNode: 0x283313300 | 1 child>)
<<<

everything is ok here, but then after I call the same print method from the button click in a few seconds I get another output

>>> 3
node: <SCNNode: 0x283313300 | 3 children>, parent is: nil
node: <SCNNode: 0x283318500 pos(-0.002828 0.016848 0.034329) rot(0.229921 0.895326 -0.381477 0.336716) scale(1.000000 1.000000 1.000000) | camera=<SCNCamera: 0x1065261c0> | no child>, parent is: Optional(<SCNNode: 0x283313300 | 3 children>)
node: <SCNNode: 0x283336d00 | light=<SCNLight: 0x103973dd0 | type=probe> | no child>, parent is: Optional(<SCNNode: 0x283313300 | 3 children>)
node: <SCNNode: 0x283324800 pos(-0.007079 -0.074922 0.031407) rot(0.000000 -1.000000 0.000000 1.474911) | light=<SCNLight: 0x103985120 | type=probe> | no child>, parent is: Optional(<SCNNode: 0x283313300 | 3 children>)
<<<

It has already had 3 children instead of one, how?? and then after a few seconds more I try to click again and get another output

>>> 3
node: <SCNNode: 0x283313300 | 4 children>, parent is: nil
node: <SCNNode: 0x283318500 pos(0.000974 0.011970 0.039510) rot(0.231398 0.878019 -0.418974 0.304382) scale(1.000000 1.000000 1.000000) | camera=<SCNCamera: 0x1065261c0> | no child>, parent is: Optional(<SCNNode: 0x283313300 | 4 children>)
node: <SCNNode: 0x283336d00 | light=<SCNLight: 0x103973dd0 | type=probe> | no child>, parent is: Optional(<SCNNode: 0x283313300 | 4 children>)
node: <SCNNode: 0x283324800 pos(-0.007079 -0.074922 0.031407) rot(0.000000 -1.000000 0.000000 1.474911) | light=<SCNLight: 0x11aceec70 | type=probe> | no child>, parent is: Optional(<SCNNode: 0x283313300 | 4 children>)
node: <SCNNode: 0x28332ac00 pos(-0.007079 -0.074922 0.031407) rot(0.000000 -1.000000 0.000000 1.474911) | light=<SCNLight: 0x11b908130 | type=probe> | no child>, parent is: Optional(<SCNNode: 0x283313300 | 4 children>)
<<<

It has 4 children, interesting huh?

Could it be related to the configuration? Like the ARKit tried to create the light nodes related to the real light ambiance in order to simulate it on the scene or something like this?

UPD

Thanks to @mnuages, really this property automaticallyUpdatesLighting seems very close to being the right solution, I set it in viewDidLoad like this scnView.automaticallyUpdatesLighting = false, but it doesn't make difference in my case, I still see that light nodes are adding.

UPD2

My current implementation is -

...
override func viewWillAppear(_ animated: Bool) {
        let config = ARWorldTrackingConfiguration()
        config.environmentTexturing = .automatic
        scnView.session.run(config)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        scnView.scene = SCNScene()
        scnView.scene.lightingEnvironment.contents = .none
        scnView.scene.background.contents = .none
        scnView.automaticallyUpdatesLighting = false
        
        scnView.delegate = self
        scnView.showsStatistics = true
...

But the problem is still reproducable.

Upvotes: 3

Views: 271

Answers (3)

Andy Jazz
Andy Jazz

Reputation: 58553

I think you're talking about SceneKit Procedural Sky. You can turn it OFF using the following command:

scnVue.scene?.lightingEnvironment.contents = .none      // Probe Light

scnVue.scene?.background.contents = .none               // Image

Or, you can turn skybox ON programmatically:

scnVue.scene?.background.contents = MDLSkyCubeTexture(name: "heaven",
                                           channelEncoding: .float32,
                                         textureDimensions: vector_int2(512, 
                                                                        512),
                                                 turbidity: 0.12,
                                              sunElevation: 1.00,
                                 upperAtmosphereScattering: 0.05,
                                              groundAlbedo: 0.32)

scnVue.scene?.lightingEnvironment.contents = scnVue.scene?.background.contents

scnVue.scene?.lightingEnvironment.intensity = 1.5

P.S.

If you're using ship.scn scene, you may remember that Procedural Sky there is turned ON.

Upvotes: 1

Sirop4ik
Sirop4ik

Reputation: 5263

Eventually, the problem was in ar configuration

ARKit automatically adds light probes when environment texturing is enabled. You can disable this behavior by setting the environmentTexturing property's value in your configuration to .none.

Upvotes: 0

mnuages
mnuages

Reputation: 13462

Do you have the automaticallyUpdatesLighting property set on the view?

From the documentation:

If this value is true (the default), the view automatically creates one or more SCNLight objects, adds them to the scene, and updates their properties to reflect estimated lighting information from the camera scene. Set this value to false if you want to directly control all lighting in the SceneKit scene.

Upvotes: 1

Related Questions