scenekitscnnodearkitscnlight

SCNNode clone() adds more light to the scene as nodes are cloned


i am trying to add multiple 3d objects with shadows in my ARKit code.

I create node like this

  func loadNodaA()
{

    isObjectCoordinatesAtCentre = false

    let scaleFactor = 0.005

    let dragonScene = SCNScene(named:"art.scnassets/Lowpoly_tree_sample.dae")!

    let queenNode = dragonScene.rootNode.childNode(withName: "Tree_lp_11", recursively: true)

    let geometry : SCNGeometry = (queenNode?.geometry)!

    geometry.materials = [self.CreateMaterialWithName("streakedmetal")];

    nodeA = dragonScene.rootNode
    nodeA.position = SCNVector3Zero
    nodeA.scale = SCNVector3(x: Float(scaleFactor), y: Float(scaleFactor), z: Float(scaleFactor))
    nodeA.position = SCNVector3Make(0,0,0)

}

And once ARKIT detects a plane, i create a plane like this:

  func createPlaneNode(anchor: ARPlaneAnchor) -> SCNNode {

    let floatwidth = anchor.extent.x
    let floatlength = anchor.extent.z
    let floatPlaneHeight : Float = 0.001

    let planeGeometry = SCNBox(width: CGFloat(floatwidth), height: CGFloat(floatPlaneHeight), length: CGFloat(floatlength), chamferRadius:0)

    planesGeometries[anchor.identifier] = planeGeometry

    let planeNode = SCNNode(geometry: planeGeometry)

    let transparentMaterial : SCNMaterial = SCNMaterial()
    //transparentMaterial.diffuse.contents = UIImage.init(named: "art.scnassets/GridtextureGrayLines.png")

    transparentMaterial.diffuse.contents = UIImage.init(named: "art.scnassets/sunmica.png")

        //planeGeometry.materials = [transparentMaterial, transparentMaterial, transparentMaterial, transparentMaterial,self.CreateMaterialWithName("redbricks"), transparentMaterial];
    //planeGeometry.materials = [transparentMaterial]

    planeGeometry.firstMaterial = transparentMaterial

    transparentMaterial.diffuse.contentsTransform = SCNMatrix4MakeScale(2,2, 0)

    planeNode.geometry?.firstMaterial?.diffuse.wrapS = .repeat
    planeNode.geometry?.firstMaterial?.diffuse.wrapT = .repeat
    planeNode.position = SCNVector3Make(0, -(floatPlaneHeight/2), 0)

    planeNode.physicsBody = SCNPhysicsBody(type: .kinematic, shape: SCNPhysicsShape(geometry: planeGeometry, options: nil))

    //planeNode.castsShadow = true


    self.setTextureScale(plane: planeNode, planeGeometry: planeGeometry)

    return planeNode

}

And on tap of the plane i am adding tree objects with shadows to it. But the problem is when i clone these objects again and again, the plane below the trees gets more brightness i think light node that i am adding keeps on adding for each node although i am trying to delete it by name.

func insertGeometry(_ anchor : ARHitTestResult ) {



    let h = CGFloat(selectedNode.boundingBox.max.y - selectedNode.boundingBox.min.y)



    var insertionYOffset: Float = Float(h)/2.0;

    if isObjectCoordinatesAtCentre == false
    {
        insertionYOffset = 0
    }



    let hitPointPosition = SCNVector3Make(
        anchor.worldTransform.columns.3.x,
        anchor.worldTransform.columns.3.y + insertionYOffset,
        anchor.worldTransform.columns.3.z
    );

    var nodeClone = SCNNode.init()

    if CurrentNodeChoise == 1
    {
        //This means draw tree
        nodeClone = nodeA.clone()
    }

    nodeClone.position = hitPointPosition
    sceneView.scene.rootNode.addChildNode(nodeClone)



    guard let spotlightNode : SCNNode = (sceneView.scene.rootNode.childNode(withName: "LightForShadows", recursively: true)) else {


        let spot = SCNLight()
        spot.type = .spot
        spot.castsShadow = true
        spot.color = UIColor.darkGray
        spot.shadowMode = .forward
        spot.intensity = 2000
        spot.shadowRadius = 5;
        spot.shadowSampleCount = 20;
        spot.shadowMapSize = CGSize(width: 4000, height: 4000)
        spot.orthographicScale=50;
        spot.zNear=1;
        spot.zFar=1000;
        spot.name = "myLight"
        let spotNode = SCNNode()
        spotNode.light = spot
        spotNode.position = SCNVector3(x:4, y: 6, z: 0)            
        let lookAt = SCNLookAtConstraint.init(target: nodeClone)
        constraintsArray.append(lookAt)
        spotNode.constraints = constraintsArray            
        spotNode.name = "LightForShadows"        
        sceneView.scene.rootNode.addChildNode(spotNode)

        return
    }

    let lookAt = SCNLookAtConstraint.init(target: nodeClone)

    constraintsArray.append(lookAt)

    spotlightNode.constraints = constraintsArray
}

i also tried to add light to the first node only and then for rest of the nodes by just updating the first light node. But this is also not working. I want trees to get added with shadows with plane below it remaining same. Also the shadows are not perfect is there a way to make them better?

See screenshots how plane below trees changes on adding trees one by one.

First Image

Second Image

Third Image


Solution

  • For every tree you add you add a light, of course that makes your plane brighter.

    Stick with one light you create in your scene set up and just update it's constraint to point at the plane. You don't need to do anything with the lightning when you add other nodes. When your scene has a light that creates shadows this will effect every node you add.

    To make your shadows "look better" - whatever that means - you need to play around with the different lightning modes and light parameters. I'd recommend creating a scene in the Xcode editor and play around with the properties.