热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何在SpriteKit中模糊场景?-HowDoIBluraSceneinSpriteKit?

HowwouldIaddagaussianblurtoallnodes(theresnofixednumberofnodes)inanSKSceneinSpr

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 my pause menu. Almost anything would help!

如何在SpriteKit中的SKScene中为所有节点添加高斯模糊(没有固定数量的节点)?稍后将在场景顶部添加标签,这将是我的暂停菜单。几乎任何事都有帮助!

Something like this is what I'm going for: Gaussian pause menu

这样的事情就是我想要的:

6 个解决方案

#1


30  

What you're looking for is an SKEffectNode. It applies a CoreImage filter to itself (and thus all subnodes). Just make it the root view of your scene, give it one of CoreImage's blur filters, and you're set.

您正在寻找的是SKEffectNode。它将CoreImage过滤器应用于自身(以及所有子节点)。只需将它作为场景的根视图,给它一个CoreImage的模糊滤镜,然后就可以了。

For example, I set up an SKScene with an SKEffectNode as it's first child node and a property, root that holds a weak reference to it:

例如,我设置了一个带有SKEffectNode的SKScene作为它的第一个子节点和一个属性,root用于保存对它的弱引用:

-(void)createLayers{
  SKEffectNode *node = [SKEffectNode node];
  [node setShouldEnableEffects:NO];
  CIFilter *blur = [CIFilter filterWithName:@"CIGaussianBlur" keysAndValues:@"inputRadius", @1.0f, nil];
  [node setFilter:blur];
  [self setRoot:node];
}

And here's the method I use to (animate!) the blur of my scene:

这是我用来(动画!)场景模糊的方法:

-(void)blurWithCompletion:(void (^)())handler{
  CGFloat duration = 0.5f;
  [[self root] setShouldRasterize:YES];
  [[self root] setShouldEnableEffects:YES];
  [[self root] runAction:[SKAction customActionWithDuration:duration actionBlock:^(SKNode *node, CGFloat elapsedTime){
    NSNumber *radius = [NSNumber numberWithFloat:(elapsedTime/duration) * 10.0];
    [[(SKEffectNode *)node filter] setValue:radius forKey:@"inputRadius"];
  }] completion:handler];
}

Note that, like you, I'm using this as a pause screen, so I rasterize the scene. If you want your scene to animate while blurred, you should probably setShouldResterize: to NO.

请注意,像你一样,我将它用作暂停屏幕,所以我光栅化了场景。如果你希望你的场景在模糊的情况下进行动画制作,你应该将theShouldResterize:设置为NO。

And if you're not interested in animating the transition to the blur, you could always just set the filter to an initial radius of 10.0f or so and do a simple setShouldEnableEffects:YES when you want to switch it on.

如果你对动画转换到模糊不感兴趣,你可以随时将过滤器设置为初始半径10.0f左右,并且当你想要打开它时,做一个简单的setShouldEnableEffects:YES。

See also: SKEffectNode class reference

另请参见:SKEffectNode类引用

UPDATE:
See Markus's comment below. He points out that SKScene is, in fact, a subclass of SKEffectNode, so you really ought to be able to call all of this on the scene itself rather than arbitrarily inserting an effect node in your node tree.

更新:见下面Markus的评论。他指出SKScene实际上是SKEffectNode的子类,所以你真的应该能够在场景中调用所有这些,而不是在节点树中任意插入效果节点。

#2


11  

To add to this by using @Bendegúz's answer and code from http://www.bytearray.org/?p=5360

使用@Bendegúz的答案和代码从http://www.bytearray.org/?p=5360添加到此

I was able to get this to work in my current game project that's being done in IOS 8 Swift. Done a bit differently by returning an SKSpriteNode instead of a UIImage. Also note that my unwrapped currentScene.view! call is to a weak GameScene reference but should work with self.view.frame based on where you are calling these methods. My pause screen is called in a separate HUD class hence why this is the case.

我能够在我目前正在IOS 8 Swift中完成的游戏项目中使用它。通过返回SKSpriteNode而不是UIImage来完成一些不同的操作。另请注意我的unwrapped currentScene.view! call是一个弱的GameScene引用,但应该根据你调用这些方法的位置使用self.view.frame。我的暂停屏幕在一个单独的HUD类中调用,因此为什么会这样。

I would imagine this could be done more elegantly, maybe more like @jemmons's answer. Just wanted to possibly help out anyone else trying to do this in SpriteKit projects written in all or some Swift code.

我想这可以做得更优雅,也许更像是@ jemmons的回答。只是想在可能用SpriteKit项目编写的全部或部分Swift代码中帮助其他人。

func getBluredScreenshot() -> SKSpriteNode{

    create the graphics context
    UIGraphicsBeginImageContextWithOptions(CGSize(width: currentScene.view!.frame.size.width, height: currentScene.view!.frame.size.height), true, 1)

    currentScene.view!.drawViewHierarchyInRect(currentScene.view!.frame, afterScreenUpdates: true)

    // retrieve graphics context
    let cOntext= UIGraphicsGetCurrentContext()

    // query image from it
    let image = UIGraphicsGetImageFromCurrentImageContext()

    // create Core Image context
    let ciCOntext= CIContext(options: nil)
    // create a CIImage, think of a CIImage as image data for processing, nothing is displayed or can be displayed at this point
    let coreImage = CIImage(image: image)
    // pick the filter we want
    let filter = CIFilter(name: "CIGaussianBlur")
    // pass our image as input
    filter.setValue(coreImage, forKey: kCIInputImageKey)

    //edit the amount of blur
    filter.setValue(3, forKey: kCIInputRadiusKey)

    //retrieve the processed image
    let filteredImageData = filter.valueForKey(kCIOutputImageKey) as CIImage
    // return a Quartz image from the Core Image context
    let filteredImageRef = ciContext.createCGImage(filteredImageData, fromRect: filteredImageData.extent())
    // final UIImage
    let filteredImage = UIImage(CGImage: filteredImageRef)

    // create a texture, pass the UIImage
    let texture = SKTexture(image: filteredImage!)
    // wrap it inside a sprite node
    let sprite = SKSpriteNode(texture:texture)

    // make image the position in the center
    sprite.position = CGPointMake(CGRectGetMidX(currentScene.frame), CGRectGetMidY(currentScene.frame))

    var scale:CGFloat = UIScreen.mainScreen().scale

    sprite.size.width  *= scale

    sprite.size.height *= scale

    return sprite


}


func loadPauseBGScreen(){

    let duration = 1.0

    let pauseBG:SKSpriteNode = self.getBluredScreenshot()

    //pauseBG.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
    pauseBG.alpha = 0
    pauseBG.zPosition = self.zPosition + 1
    pauseBG.runAction(SKAction.fadeAlphaTo(1, duration: duration))

    self.addChild(pauseBG)

}

#3


9  

This is my solution for the pause screen. It will take a screenshot, blur it and after that show it with animation. I think you should do it if you don't wanna waste to much fps.

这是我暂停屏幕的解决方案。它会截取屏幕,模糊它,然后用动画显示它。我想你应该这样做,如果你不想浪费很多fps。

-(void)pause {
    SKSpriteNode *pauseBG = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImage:[self getBluredScreenshot]]];
    pauseBG.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
    pauseBG.alpha = 0;
    pauseBG.zPosition = 2;
    [pauseBG runAction:[SKAction fadeAlphaTo:1 duration:duration / 2]];
    [self addChild:pauseBG];
}

And this is the helper method:

这是辅助方法:

- (UIImage *)getBluredScreenshot {
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 1);
    [self.view drawViewHierarchyInRect:self.view.frame afterScreenUpdates:YES];
    UIImage *ss = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    CIFilter *gaussianBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
    [gaussianBlurFilter setDefaults];
    [gaussianBlurFilter setValue:[CIImage imageWithCGImage:[ss CGImage]] forKey:kCIInputImageKey];
    [gaussianBlurFilter setValue:@10 forKey:kCIInputRadiusKey];

    CIImage *outputImage = [gaussianBlurFilter outputImage];
    CIContext *cOntext= [CIContext contextWithOptions:nil];
    CGRect rect          = [outputImage extent];
    rect.origin.x        += (rect.size.width  - ss.size.width ) / 2;
    rect.origin.y        += (rect.size.height - ss.size.height) / 2;
    rect.size            = ss.size;
    CGImageRef cgimg     = [context createCGImage:outputImage fromRect:rect];
    UIImage *image       = [UIImage imageWithCGImage:cgimg];
    CGImageRelease(cgimg);
    return image;
}

#4


2  

This is another example of getting this done in swift 2 without the layers:

这是在没有图层的情况下在swift 2中完成此操作的另一个示例:

func blurWithCompletion() {
let duration: CGFloat = 0.5
let filter: CIFilter = CIFilter(name: "CIGaussianBlur", withInputParameters: ["inputRadius" : NSNumber(double:1.0)])!
scene!.filter = filter
scene!.shouldRasterize = true
scene!.shouldEnableEffects = true
scene!.runAction(SKAction.customActionWithDuration(0.5, actionBlock: { (node: SKNode, elapsedTime: CGFloat) in
    let radius = (elapsedTime/duration)*10.0
    (node as? SKEffectNode)!.filter!.setValue(radius, forKey: "inputRadius")

}))

}

}

#5


1  

Swift 3 Update: This is @Chuck Gaffney's answer updated for Swift 3. I know this question is tagged objective-c, but this page ranked 2nd in Google for "swift spritekit blur". I changed currentScene to self.

Swift 3更新:这是@Chuck Gaffney对Swift 3更新的答案。我知道这个问题被标记为objective-c,但是这个页面在Google中排名第二,因为“swift spritekit模糊”。我把currentScene改成了自己。

    func getBluredScreenshot() -> SKSpriteNode{

    //create the graphics context
    UIGraphicsBeginImageContextWithOptions(CGSize(width: self.view!.frame.size.width, height: self.view!.frame.size.height), true, 1)

    self.view!.drawHierarchy(in: self.view!.frame, afterScreenUpdates: true)

    // retrieve graphics context
    _ = UIGraphicsGetCurrentContext()

    // query image from it
    let image = UIGraphicsGetImageFromCurrentImageContext()

    // create Core Image context
    let ciCOntext= CIContext(options: nil)
    // create a CIImage, think of a CIImage as image data for processing, nothing is displayed or can be displayed at this point
    let coreImage = CIImage(image: image!)
    // pick the filter we want
    let filter = CIFilter(name: "CIGaussianBlur")
    // pass our image as input
    filter?.setValue(coreImage, forKey: kCIInputImageKey)

    //edit the amount of blur
    filter?.setValue(3, forKey: kCIInputRadiusKey)

    //retrieve the processed image
    let filteredImageData = filter?.value(forKey: kCIOutputImageKey) as! CIImage
    // return a Quartz image from the Core Image context
    let filteredImageRef = ciContext.createCGImage(filteredImageData, from: filteredImageData.extent)
    // final UIImage
    let filteredImage = UIImage(cgImage: filteredImageRef!)

    // create a texture, pass the UIImage
    let texture = SKTexture(image: filteredImage)
    // wrap it inside a sprite node
    let sprite = SKSpriteNode(texture:texture)

    // make image the position in the center
    sprite.position = CGPoint(x: self.frame.midX, y: self.frame.midY)

    let scale:CGFloat = UIScreen.main.scale

    sprite.size.width  *= scale

    sprite.size.height *= scale

    return sprite


}

func loadPauseBGScreen(){

    let duration = 1.0

    let pauseBG:SKSpriteNode = self.getBluredScreenshot()

    pauseBG.alpha = 0
    pauseBG.zPosition = self.zPosition + 1
    pauseBG.run(SKAction.fadeAlpha(to: 1, duration: duration))

    self.addChild(pauseBG)

}

#6


1  

Swift 4:

斯威夫特4:

add this to your gameScene if you want to blur everything in the scene:

如果要模糊场景中的所有内容,请将其添加到gameScene中:

let  blur = CIFilter(name:"CIGaussianBlur",withInputParameters: ["inputRadius": 10.0])
        self.filter = blur
        self.shouldRasterize = true
        self.shouldEnableEffects = false

change self.shouldEnableEffects = true when you want to use it.

如果要使用它,请更改self.shouldEnableEffects = true。


推荐阅读
  • iOS Swift中如何实现自动登录?
    本文介绍了在iOS Swift中如何实现自动登录的方法,包括使用故事板、SWRevealViewController等技术,以及解决用户注销后重新登录自动跳转到主页的问题。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • [echarts] 同指标对比柱状图相关的知识介绍及应用示例
    本文由编程笔记小编为大家整理,主要介绍了echarts同指标对比柱状图相关的知识,包括对比课程通过率最高的8个课程和最低的8个课程以及全校的平均通过率。文章提供了一个应用示例,展示了如何使用echarts制作同指标对比柱状图,并对代码进行了详细解释和说明。该示例可以帮助读者更好地理解和应用echarts。 ... [详细]
  • 本文介绍了利用ARMA模型对平稳非白噪声序列进行建模的步骤及代码实现。首先对观察值序列进行样本自相关系数和样本偏自相关系数的计算,然后根据这些系数的性质选择适当的ARMA模型进行拟合,并估计模型中的位置参数。接着进行模型的有效性检验,如果不通过则重新选择模型再拟合,如果通过则进行模型优化。最后利用拟合模型预测序列的未来走势。文章还介绍了绘制时序图、平稳性检验、白噪声检验、确定ARMA阶数和预测未来走势的代码实现。 ... [详细]
  • 用户视图(查看运行状态或其他参数)系统视图(配置设备的系统参数)system-viewEntersystemview,returnuservi ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
  • QuestionThereareatotalofncoursesyouhavetotake,labeledfrom0ton-1.Somecoursesmayhaveprerequi ... [详细]
author-avatar
袁冠和堂
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有