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
Рендеринг размытого статического изображения из суперпредставления -> поместите UIImageView в OptionsView, с помощью clipsToBounds = true -> анимируйте позицию UIImageView при анимировании позиции optionsView, чтобы размытие оставалось неподвижным относительно суперпредставления
Забудьте о 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
}
}
Результат:
Есть несколько проблем, хотя
Обрезка не работает со SKEffectNode до тех пор, пока ее свойство shouldRasterize не будет установлено в значение true. Я получаю весь экран размытым. Так что я до сих пор не знаю, как правильно реализовать размытие в реальном времени.
Анимация на 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, поэтому, очевидно, что оно не идеально для некоторых вещей, но, надеюсь, это поможет.