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的一些问题。
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];
}
}
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子类,您可以在核心映像中创建一个辉光效果。这样的过滤器将包括以下步骤:
CIColorMatrix
to create a monochrome version of the input image.CIAffineTransform
+ CIGaussianBlur
).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模板中运行:
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电脑上,你可能有多余的硅……但如果你想在游戏中做到这一点,记住以下几点:
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.) 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要容易得多,后者很可能是您拥有的另一个逻辑选项。