How Do I Blur a Scene in SpriteKit?

后端 未结 7 831
北恋
北恋 2020-11-28 06:00

How would I add a gaussian blur to all nodes (there\'s no fixed number of nodes) in an SKScene in SpriteKit? A label will be added on top of the scene later, this will be m

相关标签:
7条回答
  • 2020-11-28 06:40

    I was trying to do this same thing now, in May 2020 (Xcode 11 and iOS 13.x), but wasn't unable to 'animate' the blur radius. In my case, I start with the scene fully blurred, and then 'unblur' it gradually (set inputRadius to 0).

    Somehow, the new input radius value set in the custom action block wasn't reflected in the rendered scene. My code was as follows:

        private func unblur() {
            run(SKAction.customAction(withDuration: unblurDuration, actionBlock: { [weak self] (_, elapsed) in
                guard let this = self else { return }
                let ratio = (TimeInterval(elapsed) / this.unblurDuration)
                let radius = this.maxBlurRadius * (1 - ratio) // goes to 0 as ratio goes to 1
                this.filter?.setValue(radius, forKey: kCIInputRadiusKey)
            }))
        }
    

    I even tried updating the value manually using SKScene.update(_:) and some variables for time book-keeping, but the same result.

    It occurred to me that perhaps I could force the refresh if I "re-assingned" the blur filter to the .filter property of my SKScene (see comments in ALL CAPS near the end of the code), to the same effect, and it worked.

    The full code:

    class MyScene: SKScene {
    
        private let maxBlurRadius: Double = 50
        private let unblurDuration: TimeInterval = 5
    
        init(size: CGSize) {
            super.init(size: size)
    
            let filter = CIFilter(name: "CIGaussianBlur")
            filter?.setValue(maxBlurRadius, forKey: kCIInputRadiusKey)
            self.filter = filter
            self.shouldEnableEffects = true
            self.shouldRasterize = false
    
            // (...rest of the child nodes, etc...)
    
        }
    
        override func didMove(to view: SKView) {
            super.didMove(to: view)
            self.unblur()
        }
    
        private func unblur() {
            run(SKAction.customAction(withDuration: unblurDuration, actionBlock: { [weak self] (_, elapsed) in
                guard let this = self else { return }
                let ratio = (TimeInterval(elapsed) / this.unblurDuration)
                let radius = this.maxBlurRadius * (1 - ratio) // goes to 0 as ratio goes to 1
    
                // OBTAIN THE FILTER
                let filter = this.filter
    
                // MODIFY ATTRIBUTE 
                filter?.setValue(radius, forKey: kCIInputRadiusKey)
    
                // RE=ASSIGN TO SCENE
                this.filter = filter
            }))
        }
    }
    
    

    I hope this helps someone!

    0 讨论(0)
提交回复
热议问题