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

如何通过SKEffectNode在精灵周围创建一个辉光-HowcanyoucreateaglowaroundaspriteviaSKEffectNode

IhaveaSKSpriteNodethatIdliketohaveablueglowarounditsedgesforhighlightingpurposes.

I have a SKSpriteNode that I'd like to have a blue glow around it's edges for highlighting purposes. I am guessing that I would need to make my sprite a child of a SKEffectNode and then create/apply a filter of some sort.

我有一个SKSpriteNode我想要在它的边缘周围有一个蓝色的光圈,以突出显示。我猜想,我需要把我的sprite变成一个SKEffectNode的孩子,然后创建/应用某种过滤器。

UPDATE : I have investigated this quite a it with the chosen answer's approach, and discovered that SKEffectNode has a sizeable hit on performance even if you have it set to shouldRasterize and 'no filter' defined. My conclusion is that if your game requires more than 10 moving objects at one time, they can't involve a SKEffectNode even if rasterized.

更新:我用所选答案的方法研究了相当多的it,发现SKEffectNode在性能上受到了很大的影响,即使您将它设置为shouldRasterize和'no filter'。我的结论是,如果你的游戏一次需要10个以上的移动对象,即使是光栅化的,也不能涉及到SKEffectNode。

My solution will likely involve pre-rendered glow images/animations, as SKEffectNode is not going to cut it for my requirements.

我的解决方案可能会涉及预渲染的辉光图像/动画,因为SKEffectNode不会按照我的要求裁剪它。

If someone has insight as to anything I am missing, I'd appreciate hearing whatever you know!

如果有人能洞悉我所错过的一切,我将感激你所知道的一切!

I am accepting an answer because it does achieve what I asked for, but wanted to add these notes to anyone looking to go this route, so you can be aware of some of the issues with using SKEffectNode.

我正在接受一个答案,因为它确实实现了我所要求的,但是想要将这些注释添加到任何想要走这条路线的人,这样您就可以知道使用SKEffectNode的一些问题。

3 个解决方案

#1


27  

@rickster's answer is great. Since I have low rep, I'm apparently not allowed to add this code as a comment to his. I hope this doesn't break stackoverflow rules of propriety. I'm not trying to userp his rep in any way.

@rickster的回答是伟大的。由于我有一个低代表,我显然不允许添加这段代码作为他的评论。我希望这不会违反stackoverflow的礼节规则。我不会试图以任何方式利用他的代表。

Here's code that does what he's describing in his answer:

这是他在回答中所描述的代码

Header:

标题:

//  ENHGlowFilter.h
#import 

@interface ENHGlowFilter : CIFilter

@property (strong, nonatomic) UIColor *glowColor;
@property (strong, nonatomic) CIImage *inputImage;
@property (strong, nonatomic) NSNumber *inputRadius;
@property (strong, nonatomic) CIVector *inputCenter;

@end

//Based on ASCGLowFilter from Apple

Implementation:

实现:

#import "ENHGlowFilter.h"

@implementation ENHGlowFilter

-(id)init
{
    self = [super init];
    if (self)
    {
        _glowColor = [UIColor whiteColor];
    }
    return self;
}

- (NSArray *)attributeKeys {
    return @[@"inputRadius", @"inputCenter"];
}

- (CIImage *)outputImage {
    CIImage *inputImage = [self valueForKey:@"inputImage"];
    if (!inputImage)
        return nil;

    // Monochrome
    CIFilter *mOnochromeFilter= [CIFilter filterWithName:@"CIColorMatrix"];
    CGFloat red = 0.0;
    CGFloat green = 0.0;
    CGFloat blue = 0.0;
    CGFloat alpha = 0.0;
    [self.glowColor getRed:&red green:&green blue:&blue alpha:&alpha];
    [monochromeFilter setDefaults];
    [monochromeFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:red] forKey:@"inputRVector"];
    [monochromeFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:green] forKey:@"inputGVector"];
    [monochromeFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:blue] forKey:@"inputBVector"];
    [monochromeFilter setValue:[CIVector vectorWithX:0 Y:0 Z:0 W:alpha] forKey:@"inputAVector"];
    [monochromeFilter setValue:inputImage forKey:@"inputImage"];
    CIImage *glowImage = [monochromeFilter valueForKey:@"outputImage"];

    // Scale
    float centerX = [self.inputCenter X];
    float centerY = [self.inputCenter Y];
    if (centerX > 0) {
        CGAffineTransform transform = CGAffineTransformIdentity;
        transform = CGAffineTransformTranslate(transform, centerX, centerY);
        transform = CGAffineTransformScale(transform, 1.2, 1.2);
        transform = CGAffineTransformTranslate(transform, -centerX, -centerY);

        CIFilter *affineTransformFilter = [CIFilter filterWithName:@"CIAffineTransform"];
        [affineTransformFilter setDefaults];
        [affineTransformFilter setValue:[NSValue valueWithCGAffineTransform:transform] forKey:@"inputTransform"];
        [affineTransformFilter setValue:glowImage forKey:@"inputImage"];
        glowImage = [affineTransformFilter valueForKey:@"outputImage"];
    }

    // Blur
    CIFilter *gaussianBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
    [gaussianBlurFilter setDefaults];
    [gaussianBlurFilter setValue:glowImage forKey:@"inputImage"];
    [gaussianBlurFilter setValue:self.inputRadius ?: @10.0 forKey:@"inputRadius"];
    glowImage = [gaussianBlurFilter valueForKey:@"outputImage"];

    // Blend
    CIFilter *blendFilter = [CIFilter filterWithName:@"CISourceOverCompositing"];
    [blendFilter setDefaults];
    [blendFilter setValue:glowImage forKey:@"inputBackgroundImage"];
    [blendFilter setValue:inputImage forKey:@"inputImage"];
    glowImage = [blendFilter valueForKey:@"outputImage"];

    return glowImage;
}


@end

In use:

在使用:

@implementation ENHMyScene //SKScene subclass

-(id)initWithSize:(CGSize)size {    
    if (self = [super initWithSize:size]) {
        /* Setup your scene here */
        [self setAnchorPoint:(CGPoint){0.5, 0.5}];
        self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];

        SKEffectNode *effectNode = [[SKEffectNode alloc] init];
        ENHGlowFilter *glowFilter = [[ENHGlowFilter alloc] init];
        [glowFilter setGlowColor:[[UIColor redColor] colorWithAlphaComponent:0.5]];
        [effectNode setShouldRasterize:YES];
        [effectNode setFilter:glowFilter];
        [self addChild:effectNode];
        _effectNode = effectNode;
    }
    return self;
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */

    for (UITouch *touch in touches) {
        CGPoint location = [touch locationInNode:self];
        SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];
        sprite.position = location;
        [self.effectNode addChild:sprite];
    }
}

#2


22  

You can create a glow effect in Core Image by creating a CIFilter subclass that composes multiple built-in filters. Such a filter would involve steps like these:

通过创建一个包含多个内置过滤器的CIFilter子类,您可以在核心映像中创建一个辉光效果。这样的过滤器将包括以下步骤:

  1. Create an image to be used as the blue glow. There's probably a few decent ways to do this; one is to use CIColorMatrix to create a monochrome version of the input image.
  2. 创建一个用作蓝色辉光的图像。可能有一些不错的方法;一种是使用CIColorMatrix创建输入图像的单色版本。
  3. Scale up and blur the glow image (CIAffineTransform + CIGaussianBlur).
  4. 放大和模糊辉光图像(CIAffineTransform + CIGaussianBlur)。
  5. Composite the original input image over the glow image (CISourceOverCompositing).
  6. 在辉光图像上组合原始输入图像(CISourceOverCompositing)。

Once you have a CIFilter subclass that does all that, you can use it with a SKEffectNode to get a realtime glow around the effect node's children. Here it is running in the "Sprite Kit Game" Xcode template on an iPad 4:

一旦您有了一个CIFilter子类来完成所有这些工作,您就可以将它与一个SKEffectNode一起使用,从而在effect节点的子节点周围获得实时的辉光。它在ipad4的“Sprite Kit Game”Xcode模板中运行:

Glowing spaceship in Sprite Kit

I got this up and running in a few minutes by cribbing the custom filter class used for a similar effect in the Scene Kit presentation from WWDC 2013 -- grab it from the WWDC Sample Code package at developer.apple.com/downloads, and look for the ASCGlowFilter class. (If you want to use that code on iOS, you'll need to change the NSAffineTransform part to use CGAffineTransform instead. I also replaced the centerX and centerY properties with an inputCenter parameter of type CIVector so Sprite Kit can automatically center the effect on the sprite.)

我在WWDC 2013年的场景工具包演示中使用了定制过滤器类,并在几分钟内运行了它——从developer.apple.com/downloads的WWDC示例代码包中获取它,然后查找ASCGlowFilter类。(如果您想在iOS中使用该代码,则需要更改NSAffineTransform部分以使用CGAffineTransform。我还用CIVector类型的inputCenter参数替换了centerX和centerY属性,这样Sprite Kit就可以自动将效果居中。)

Did I say "realtime" glow? Yup! That's short for "really eats CPU time". Notice in the screenshot it's no longer pegged at 60 fps, even with only one spaceship -- and with the software OpenGL ES renderer on the iOS Simulator, it runs at slideshow speed. If you're on the Mac, you probably have silicon to spare... but if you want to do this in your game, keep some things in mind:

我说过"实时"辉光吗?是的!这是“真的吃了CPU时间”的缩写。请注意,在截图中,即使只有一艘宇宙飞船,它也不再以60帧每秒的速度被锁定——而iOS模拟器上的OpenGL ES渲染器软件,它的运行速度也是以幻灯片的速度。如果你在Mac电脑上,你可能有多余的硅……但如果你想在游戏中做到这一点,记住以下几点:

  • There are probably some ways to get better performance out of the filter itself. Play with different CI filters and you might see some improvement (there are several blur filters in Core Image, some of which will certainly be faster than Gaussian). Also note blur effects tend to be fragment-shader bound, so the smaller the image and the smaller the glow radius the better.
  • 可能有一些方法可以从过滤器本身获得更好的性能。使用不同的CI过滤器,您可能会看到一些改进(Core Image中有几个模糊过滤器,其中一些肯定比高斯的要快)。另外,注意模糊效果往往是碎片着色的边界,所以图像越小,辉光半径越小越好。
  • If you want to have multiple glows in a scene, consider making all the glowing sprites children of the same effect node -- that'll render them all into one image, then apply the filter once.
  • 如果你想在一个场景中有多个发光点,可以考虑把所有发光的精灵都放在同一个效果节点上——这样可以把它们全部渲染成一个图像,然后再应用一次滤镜。
  • If the sprites to be glowed don't change much (e.g. if our spaceship wasn't rotating), setting shouldRasterize to YES on the effect node should help a lot. (Actually, in this case, you might get some improvement by rotating the effect node instead of the sprite within it.)
  • 如果要发光的精灵变化不大(例如,如果我们的飞船没有旋转),那么在效果节点上设置shouldRasterize为YES应该会有很大的帮助(实际上,在这种情况下,您可以通过旋转效果节点而不是其中的精灵来获得一些改进)。
  • Do you really need realtime glow? As with many spiffy graphical effects in games, you'll get much better performance if you fake it. Make a blurry, bluey spaceship in your favorite graphics editor and put it in the scene as another sprite.
  • 你真的需要实时发光吗?就像游戏中许多华丽的图形效果一样,如果你假装它,你会得到更好的性能。在你最喜欢的图形编辑器中做一个模糊的,蓝色的宇宙飞船,把它作为另一个精灵。

#3


3  

You could use a SKShapeNode behind the sprite and define a glow using it's glowWidth and strokeColor properties. If you size and position it right, this should give you the appearance of a glow. This doesn't give you many options for customization, but I imagine it's much easier than using a CIFilter with an SKEffectNode which is likely the other logical option you have for this.

您可以使用精灵后面的SKShapeNode并使用它的glowWidth和strokeColor属性定义辉光。如果你的尺寸和位置正确,这应该会让你看起来容光焕发。这并没有为您提供许多定制选项,但我认为这比使用带有SKEffectNode的CIFilter要容易得多,后者很可能是您拥有的另一个逻辑选项。


推荐阅读
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
  • 本文将深入探讨如何在不依赖第三方库的情况下,使用 React 处理表单输入和验证。我们将介绍一种高效且灵活的方法,涵盖表单提交、输入验证及错误处理等关键功能。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文详细介绍了如何使用 Yii2 的 GridView 组件在列表页面实现数据的直接编辑功能。通过具体的代码示例和步骤,帮助开发者快速掌握这一实用技巧。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • Scala 实现 UTF-8 编码属性文件读取与克隆
    本文介绍如何使用 Scala 以 UTF-8 编码方式读取属性文件,并实现属性文件的克隆功能。通过这种方式,可以确保配置文件在多线程环境下的一致性和高效性。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 本文介绍了在Windows环境下使用pydoc工具的方法,并详细解释了如何通过命令行和浏览器查看Python内置函数的文档。此外,还提供了关于raw_input和open函数的具体用法和功能说明。 ... [详细]
  • 深入解析 Spring Security 用户认证机制
    本文将详细介绍 Spring Security 中用户登录认证的核心流程,重点分析 AbstractAuthenticationProcessingFilter 和 AuthenticationManager 的工作原理。通过理解这些组件的实现,读者可以更好地掌握 Spring Security 的认证机制。 ... [详细]
  • JavaScript实现表格数据的实时筛选功能
    本文介绍如何使用JavaScript实现对表格数据的实时筛选,帮助开发者提高用户体验。通过简单的代码示例,展示如何根据用户输入的关键字动态过滤表格内容。 ... [详细]
  • PHP 过滤器详解
    本文深入探讨了 PHP 中的过滤器机制,包括常见的 $_SERVER 变量、filter_has_var() 函数、filter_id() 函数、filter_input() 函数及其数组形式、filter_list() 函数以及 filter_var() 和其数组形式。同时,详细介绍了各种过滤器的用途和用法。 ... [详细]
  • 在创建新的Android项目时,您可能会遇到aapt错误,提示无法打开libstdc++.so.6共享对象文件。本文将探讨该问题的原因及解决方案。 ... [详细]
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • 云函数与数据库API实现增删查改的对比
    本文将深入探讨使用云函数和数据库API实现数据操作(增删查改)的不同方法,通过详细的代码示例帮助读者更好地理解和掌握这些技术。文章不仅提供代码实现,还解释了每种方法的特点和适用场景。 ... [详细]
author-avatar
赵娜supergirl
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有