scenekitarkitcifilterglowbloom

SceneKit ARKit glowing effect


Hi I'm trying to have a glowing effect around a node. I used the SCNNode filters property and set to an array of CIFilter.

It works and renders only when the node has no node behind it which I don't understand. I tried to set the rendering order and the readDepth options without success. I'm really stuck at this point and would appreciate your input!

Please see the screenshot for an example and the code sample.

func addBloom() -> [CIFilter]? {
    let bloomFilter = CIFilter(name:"CIBloom")!
    bloomFilter.setValue(10.0, forKey: "inputIntensity")
    bloomFilter.setValue(30.0, forKey: "inputRadius")

    return [bloomFilter]
}

Calling this using:

myNode.filters = addBloom() 

enter image description here

A final note, I noticed that for CIFilter to work with Metal the antiAliasing needs to be set to .none

arSceneView.antialiasingMode = .none

Thanks a lot!

Adrien


Solution

  • Have you tried setting the writesToDepthBuffer to false for those nodes which you aren't apply the filters to?

    For your information writesToDepthBuffer refers to:

    SceneKit’s rendering process uses a depth buffer to determine the ordering of rendered surfaces relative to the viewer. The default value of this property is YES, specifying that SceneKit saves depth information for each rendered pixel for use by later rendering passes. Typically, you disable writing to the depth buffer when rendering semitransparent objects, because later stages of the rendering process may require depth information about the opaque objects behind them.

    This example seems to be working fine:

    /// Generates An SCNPlane & A Red & Green SCNSphere
    func generateNodes(){
    
        let planeNode = SCNNode(geometry: SCNPlane(width: 1, height: 0.5))
        planeNode.geometry?.firstMaterial?.diffuse.contents = UIColor.black
        planeNode.position = SCNVector3(0, 0, -1)
    
        let redSphereNode = SCNNode(geometry: SCNSphere(radius: 0.1))
        redSphereNode.geometry?.firstMaterial?.diffuse.contents = UIColor.red
        redSphereNode.position = SCNVector3(-0.3, 0, -1)
        redSphereNode.filters = addBloom()
    
        let greenSphereNode = SCNNode(geometry: SCNSphere(radius: 0.1))
        greenSphereNode.geometry?.firstMaterial?.diffuse.contents = UIColor.green
        greenSphereNode.position = SCNVector3(0.3, 0, -1)
        greenSphereNode.filters = addBloom()
    
        self.augmentedRealityView.scene.rootNode.addChildNode(planeNode)
        self.augmentedRealityView.scene.rootNode.addChildNode(redSphereNode)
        self.augmentedRealityView.scene.rootNode.addChildNode(greenSphereNode)
        planeNode.geometry?.firstMaterial?.writesToDepthBuffer = false
    
    }
    
    
    /// Creates An Array Of CIBloom Filters
    ///
    /// - Returns: [CIFilter]?
    func addBloom() -> [CIFilter]? {
        let bloomFilter = CIFilter(name:"CIBloom")!
        bloomFilter.setValue(10.0, forKey: "inputIntensity")
        bloomFilter.setValue(30.0, forKey: "inputRadius")
    
        return [bloomFilter]
    }
    

    One thing to note however, which I did notice was that if I used an image with a transparent background for the contents of the SCNPlane it didn't work, although with another image it was fine.

    Hope it points you in the right direction...