2

我正在尝试模糊多个SKNode对象。我通过让父母SKEffectNode设置CIFilter@"CIGaussianBlur". 像这样:

- (SKEffectNode *)createBlurNode
{
    SKEffectNode *blurNode = [[SKEffectNode alloc] init];
    blurNode.shouldRasterize = YES;
    [blurNode setShouldEnableEffects:NO];

    [blurNode setFilter:[CIFilter filterWithName:@"CIGaussianBlur"
                                   keysAndValues:@"inputRadius", @10.0f, nil]];
    return blurNode;
}

这适用于当前屏幕上的一堆节点。但是当我将这些音符彼此远离(大约 3000 像素)时,不再发生模糊,我得到一个大黑框。无论SKNodes我模糊的是SKShapeNodes还是,都会发生这种情况SKSpriteNodes。这是一个有此问题的示例项目:示例项目。(顺便说一句,感谢 BobMoff 在这里找到的初始版本):

这是快乐的模糊(当节点彼此之间的距离小于3000 像素时):

快乐的模糊!

悲伤模糊(当节点彼此相距超过 3000 像素时)

在此处输入图像描述

更新

SKEffectNode只要 an是父级,就会发生此行为。启用效果、模糊等都无所谓,如果父节点是SKNode就可以了。即即使父模糊节点像下面这样创建,你也会得到黑度:

- (SKEffectNode *)createBlurNode
{
    SKEffectNode *blurNode = [[SKEffectNode alloc] init];

//    blurNode.shouldRasterize = YES;
//    [blurNode setShouldEnableEffects:NO];
//    [blurNode setFilter:[CIFilter filterWithName:@"CIGaussianBlur"
//                                   keysAndValues:@"inputRadius", @10.0f, nil]];
    return blurNode;
}
4

4 回答 4

5

我有一个类似的问题,我想模糊一个非常宽泛的平移场景。

为了使模糊效果发挥作用,我删除了所有超出场景边缘的节点:

// Property declarations, elsewhere in the class:
var blurNode: SKEffectNode
var mainScene: SKScene
var exParents: [SKNode : SKNode] = [:]


/**
 * Remove outlying nodes from the scene and activate the SKEffectNode
 */
func blurScene() {
    let FILTER_MARGIN: CGFloat = 100
    let widthMax: CGFloat = mainScene.size.width + FILTER_MARGIN
    let heightMax: CGFloat = mainScene.size.height + FILTER_MARGIN

    // Recursively iterate through all blurNode's children
    blurNode.enumerateChildNodesWithName(".//*", usingBlock: {
        [unowned self]
        node, stop in

        if node.parent != nil && node.scene != nil { // Ignore nodes we already removed
            if let sprite = node as? SKSpriteNode {

                // Calculate sprite node position in scene coordinates
                let sceneOrig = sprite.scene!.convertPoint(sprite.position, fromNode: sprite.parent!)

                // Find left, right, bottom and top edges of sprite
                let l = sceneOrig.x - sprite.size.width*sprite.anchorPoint.x
                let r = l + sprite.size.width
                let b = sceneOrig.y - sprite.size.height*sprite.anchorPoint.y
                let t = b + sprite.size.height

                if l < -FILTER_MARGIN || r > widthMax || b < -FILTER_MARGIN || t > heightMax {
                    self.exParents[sprite] = sprite.parent!
                    sprite.removeFromParent()
                }
            }
        }
    })

    blurNode.shouldEnableEffects = true
}

/**
 * Disable blur and reparent nodes we removed earlier
 */
func removeBlur() {
    self.blurNode.shouldEnableEffects = false

    for (kid, parent) in exParents {
        parent.addChild(kid)
    }

    exParents = [:]
}


笔记:

这确实会从效果节点中删除内容,因此极宽的节点不会出现在最终结果中:

SKEffectNode 裁剪示例

您可以看到以红色突出显示的山太突出,并从产生的模糊中移除。

此代码仅考虑SKSpriteNodes. EmptySKNodes似乎不会破坏效果节点,但如果您使用其他可见节点,如SKShapeNodesor SKLabelNodes,则必须修改此代码以包含它们。

如果您有ignoreSiblingOrder = false,此代码可能会弄乱您的 z 排序,因为您无法保证将节点添加回场景的顺序。


我试过的东西不起作用

简单地说node.hidden = true而不是使用removeFromParent()是行不通的。那太容易了;)

使用 anSKCropNode来裁剪异常内容对我不起作用。我试着让SKEffectNode父母SKCropNode和其他方式,但无论我把裁剪区域做得多么小,黑色方块都会出现。如果您迫切需要更清洁的解决方案,这可能仍然值得研究。

如此处所述,SKScenes它们是秘密的SKEffectNodes,您可以像blurNode上面一样设置它们的过滤器。SKScenes当他们的内容太大时不要显示黑屏。不幸的是,他们似乎只是默默地禁用了过滤器。同样,我可能错过了一些东西,因此如果您尝试在整个场景中应用效果,您可以进一步探索此选项。


替代解决方案

您可以按照此处的建议捕获整个屏幕的图像并对其应用过滤器。我最终选择了一个更简单的解决方案;我对我想要模糊的东西进行了通用截图,然后应用了非常重的模糊,这样你就看不到精确的细节了。我用它作为模糊的背景,你几乎看不出它不是真实的;)这也节省了大量的内存并避免了一个小的 UI 打嗝。


沉思

这是一个非常讨厌的错误,我希望 Apple 尽快提出解决方案。您可以单击这张可爱的相机图片以获取 GPU 跟踪并了解正在发生的事情:

GPU 跟踪按钮

设备似乎正在丢弃效果节点的帧缓冲区,因为它占用了太多内存。当设备上的内存压力更大时,更容易在SKEffectNode.

于 2015-08-09T20:56:02.990 回答
2

我使用了一种适用于我的游戏的方法,但它要求模糊区域保持静止不动。

在使用 Swift 3 的 iOS 10 上,我使用了 SKSpriteNode、SKView、SKEffectNode、CIFilter。我从 SKView 方法“从节点的纹理”返回的纹理创建了一个精灵,并将当前场景作为参数传递,因为它继承自 SKNode。所以基本上我是在拍摄场景的“截图”并从中创建一个精灵。然后我把它放在一个带有模糊过滤器的 SKEffectNode 中。(将“应该光栅化”设置为 true 以获得更好的性能,因为我只需要模糊一次)。最后,我将新精灵添加到场景中。从那里您可以将精灵添加到场景中并将它们放置在新的模糊节点上方。

let blurFilter = CIFilter(name: "CIGaussianBlur")!
let blurAmount = 15.0
blurFilter.setValue(blurAmount, forKey: kCIInputRadiusKey)

let blurEffect = SKEffectNode()
blurEffect.shouldRasterize = true

let screenshotNode = SKSpriteNode(texture: gameScene.view!.texture(from: gameScene))

blurEffect.addChild(screenshotNode)
blurEffect.filter = blurFilter

gameScene.addChild(blurEffect)
于 2016-09-26T20:05:28.360 回答
0

该错误的可能解决方法:

使用相机,将 WAY 缩小,这样您就可以看到背景中的大部分内容,并对该图像进行截图风格渲染。根据您的需要裁剪它,然后对其进行模糊处理。然后栅格化这个。

然后放大这个图像,如果需要的话,把它切片,并相应地放置。

于 2016-10-17T09:51:06.933 回答
0

SKEffectNode 渲染成纹理。在大多数 iOS 系统中,纹理的最大尺寸为 2048x2048。如果 SKEffectNode 试图渲染大于该值的内容,它将只使用 2048x2048 纹理,并且它之外的任何内容都不会出现在纹理中。它不会给你任何关于这种情况的错误或警告;它只是默默地做。

不,没有办法告诉 SKEffectNode 使用特定大小的纹理,并将内容平移和夹入其中。它总是使用一个覆盖所有子节点的纹理,如果纹理太大,它只是默默地使用那个 2048x2048 纹理。

于 2017-09-11T10:40:57.000 回答