UIVisualEffectView не размывает, это суперпредставление SKView

Я пишу игру SpriteKit и столкнулся с проблемой нечеткости изображения, которая лежит на SKView. Предполагается, что он будет скользить справа, когда игра приостановлена, и должен размывать содержимое родительского представления (SKView), точно так же, как панель управления в iOS 7. Вот желаемый вид:

Что я на самом деле получаю:

На самом деле вид слева не совсем черный, вы можете видеть, как блики из суперпредставления слегка борются через почти непрозрачное подпредставление, но размытие не применяется. Это ошибка / функция iOS 8, или это моя ошибка / недоразумение

Вот основы моего подкласса 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(представление: SKView):

view.addSubview(optionsView)

при нажатии на кнопку паузы:

self.optionsView.show()

PS Хотя я знаю еще два способа реализации размытия, я подумал, что это самый простой способ, поскольку мое приложение будет поддерживать только iOS8

  1. Рендеринг размытого статического изображения из суперпредставления -> поместите UIImageView в OptionsView, с помощью clipsToBounds = true -> анимируйте позицию UIImageView при анимировании позиции optionsView, чтобы размытие оставалось неподвижным относительно суперпредставления

  2. Забудьте о UIView, UIVisualEffectView и UIBlurView и используйте SKEffectNode вместе со SKCropNode.

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 не помогает.

Буду очень признателен, если кто-нибудь сможет помочь решить хотя бы одну из проблем.

Я знаю, что, возможно, немного опоздал, но у меня возникла та же проблема, и я нашел решение для создания размытия в реальном времени на части экрана. Он основан на этом руководстве: http://www.youtube.com/watch?v=eYHId0zgkdE где он использовал шейдер для размытия статического спрайта. Я расширил его урок, чтобы захватить часть экрана, а затем применил к нему размытие. Для вашей проблемы вы можете захватить под этой боковой панелью.

Во-первых, вы создаете SKSpriteNode держать захваченную текстуру. Затем в didMoveToView() Вы добавляете свой шейдер размытия к этому спрайту. (Вы можете найти файл blur.fsh на GitHub, в нижней части видео на 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, поэтому, очевидно, что оно не идеально для некоторых вещей, но, надеюсь, это поможет.

Другие вопросы по тегам