UIVisualEffectView不能模糊其SKView的父视图

4
我正在编写一个SpriteKit游戏,遇到了模糊视图的问题,它位于SKView上。当游戏暂停时,它应该从右侧滑入并模糊其父视图(SKView)的内容,就像iOS 7中的控制中心面板一样。这是期望的外观:enter image description here 但我实际得到的是:enter image description here 实际情况是,左侧的视图并不是完全黑色的,你可以看到父视图的高亮部分在几乎不透明的子视图中稍微闪烁,但没有应用任何模糊效果。这是iOS 8的bug/特性,还是我的错误/误解呢?
这是我的UIVisualEffectView子类的要点:
class OptionsView: UIVisualEffectView {
//...
    init(size: CGSize) {
        buttons = [UIButton]()
        super.init(effect: UIBlurEffect(style: .Dark))
        frame = CGRectMake(-size.width, 0, size.width, size.height)
        addButtons()
        clipsToBounds = true
    }
    func show() {
        UIView.animateWithDuration(0.3, animations: {
            self.frame.origin.x = 0
        })
    }
    func hide() {
        UIView.animateWithDuration(0.3, animations: {
            self.frame.origin.x = -self.frame.size.width
        })
    }

然后在GameScene类中: 在初始化器中:
optionsView = OptionsView(size: CGSizeMake(130, size.height))

在didMoveToView(view: SKView)方法中:

view.addSubview(optionsView)

按下暂停按钮:

self.optionsView.show()

附言:虽然我知道另外两种实现模糊视图的方法,但我认为这种方法是最简单的,因为我的应用程序只支持iOS8。

  1. 从父视图中渲染出一张模糊的静态图片 -> 在OptionsView上放置UIImageView,并将clipsToBounds设置为true -> 在动画OptionsView的位置时同时动画UIImageView的位置,以使模糊相对于父视图保持不动

  2. 忘记UIView、UIVisualEffectView和UIBlurView,使用SKEffectNode和SKCropNode一起使用。


2
Sprite Kit 视图不受 UIView 视觉效果的影响,因为 SK 使用不同的渲染路径,请使用 EffectNode 在 SKView 上实现效果。 - CodeSmile
你还可以对SKView进行快照,并将其放置为图像视图,以展示这种效果。 - ZeMoon
没错,这正是我在P.S. #1中所指的。 - alexburtnik
2个回答

2

好的,我已经成功使用SKEffectNode而不是UIVisualEffectView来实现所需的效果。 以下是代码,供遇到相同问题的人参考:

class BlurCropNode: SKCropNode {
    var blurNode: BlurNode
    var size: CGSize
    init(size: CGSize) {
        self.size = size
        blurNode = BlurNode(radius: 10)
        super.init()
        addChild(blurNode)
        let mask = SKSpriteNode (color: UIColor.blackColor(), size: size)
        mask.anchorPoint = CGPoint.zeroPoint
        maskNode = mask
    }
}

class BlurNode: SKEffectNode {
    var sprite: SKSpriteNode
    var texture: SKTexture {
        get { return sprite.texture }
        set {
            sprite.texture = newValue
            let scale = UIScreen.mainScreen().scale
            let textureSize = newValue.size()
            sprite.size = CGSizeMake(textureSize.width/scale, textureSize.height/scale)
        }
    }
    init(radius: CGFloat) {
        sprite = SKSpriteNode()
        super.init()
        sprite.anchorPoint = CGPointMake(0, 0)
        addChild(sprite)
        filter = CIFilter(name: "CIGaussianBlur", withInputParameters: ["inputRadius": radius])
        shouldEnableEffects = true
        shouldRasterize = true
    }
}

结果:

在此输入图片描述

尽管如此,还存在一些问题

  1. 在未将SKEffectNode的shouldRasterize属性设置为true之前,裁剪无法正常工作。我会得到整个屏幕模糊。因此,我仍然不知道如何正确地实现实时模糊。

  2. BlurCropNode上的动画不够流畅。由于捕获纹理并将其设置为effectNode的精灵子节点,因此一开始会有延迟。即使使用dispatch_async也无济于事。

如果有人能够帮忙解决至少一个问题,将不胜感激。


1
我知道我可能有点晚了,但我遇到了同样的问题,并找到了在屏幕一部分上创建实时模糊的解决方法。它基于这个教程:http://www.youtube.com/watch?v=eYHId0zgkdE,他使用着色器来模糊静态精灵。我扩展了他的教程,以捕获屏幕的一部分,然后将其应用于模糊效果。对于您的问题,您可以在侧边栏下方进行捕捉。
首先,您需要创建一个SKSpriteNode来保存捕获的纹理。然后,在didMoveToView()中,您可以将模糊着色器添加到该精灵中。(您可以在GitHub上找到blur.fsh文件,在youtube视频底部有链接。)
override func didMoveToView(view: SKView) {
    blurNode.shader = SKShader(fileNamed: "blur")

    self.addChild(blurNode)
}

然后,您需要捕获要模糊的视图部分,并将 SKTexture 应用于其中,在我的情况下是 blurNode
override func update(currentTime: CFTimeInterval) {
    // Hide the blurNode to avoid it be captured too.
    blurNode.hidden = true
    blurNode.texture = self.view!.textureFromNode(self, crop: blurNode.frame)
    blurNode.hidden = false
}

就是这样了。在我的iPad mini上,模糊屏幕宽度的1/3,帧率为58-59。全屏模糊帧率降至约22,因此显然不适合某些事情,但希望能有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接