Class

SKEffectNode

A node that can apply Core Image filters or SKWarpGeometry distortions to its children.

Overview

An SKEffectNode object renders its children into a buffer and optionally applies a Core Image filter to this rendered output. Because effect nodes conform to SKWarpable, you can also use them to apply distortions to nodes that don't implement the protocol such as shape and video nodes. Use effect nodes to incorporate sophisticated special effects into a scene or to cache the contents of a static subtree for faster rendering performance.Each time a new frame is rendered using the effect node, the effect node follows these steps:

  1. The effect node draws its children into a private framebuffer.

  2. It applies a Core Image effect to the private framebuffer. This stage is optional; see the filter and shouldEnableEffects properties.

  3. It blends the contents of its private framebuffer into its parent’s framebuffer, using one of the standard sprite blend modes.

  4. It discards its private framebuffer. This step is optional; see the shouldRasterize property.

Example: Applying a Special Effect

One possible use for effect nodes is to apply special effects to a node’s children, as shown in Figure 1. In this example, the effect node’s children are two sprites that provide lighting information. The effect node accumulates the effects of these lights, applies a blur filter to soften the resulting image, and then uses a multiply blend mode to apply this lighting to a texture.

Figure 1

Effect nodes applying special effects to a node’s children

Here’s how the scene generates this lighting effect:

  1. The scene has two children. The first is a textured sprite that represents the ground. The second is an effect node to apply lighting.

    let lightingNode = SKEffectNode()
    
  2. The effect node’s children are sprite nodes rendered using an additive blend mode.

    let light = SKSpriteNode(texture: lightTexture)
    light.blendMode = .add
    ...
    lightingNode.addChild(light)
    
  3. The effect node includes a filter effect to soften the lighting.

    let blurFilter = CIFilter(name: "CIBoxBlur",
                              withInputParameters: ["inputRadius": 20])
         
    lightingNode.filter = blurFilter
    

    If you specify a Core Image filter, it must be a filter that takes a single input image and produces a single output image.

  4. The effect node uses a multiplication blend mode to apply its lighting effect to the scene’s framebuffer.

    lightingNode.blendMode = .multiply
    

Example: Warping a Label

If you want to warp a node that doesn't conform to SKWarpable, for example a SKLabelNode, you can add it as a child to an effect node and assign a warp geometry to that effect node.

Listing 5 shows how you can warp a label node by adding it as a child to a SKEffectNode and assign the effect node a SKWarpGeometryGrid that pulls out the corners horizontally and stretches the center vertically.

Listing 5

Warping a label node

let labelNode = SKLabelNode(text: "SpriteKit")
labelNode.fontColor = UIColor.blue
labelNode.fontSize = 144
     
let effectNode = SKEffectNode()
effectNode.addChild(labelNode)
     
let destinationPositions: [vector_float2] = [
    vector_float2(-0.1, 1), vector_float2(0.5, 1.3), vector_float2(1.1, 1),
    vector_float2(0.1, 0.5), vector_float2(0.5, 0.5), vector_float2(0.9, 0.5),
    vector_float2(-0.1, 0), vector_float2(0.5, -0.3), vector_float2(1.1, 0)
]
     
let warpGeometryGrid = SKWarpGeometryGrid(columns: 2,
                                          rows: 2)
     
effectNode.warpGeometry = warpGeometryGrid.replacingByDestinationPositions(positions: destinationPositions)

Figure 2 shows the warped label.

Figure 2

Warped label

Warped label

Scenes Are Effect Nodes

The SKScene class is a subclass of SKEffectNode. This means that any scene can apply a filter to its contents. Although applying filters can be very expensive—not all filters are well designed for interactive effects—experimentation can help you find some interesting ways to use them.

Caching May Improve Performance of Static Content

An effect node normally discards its private framebuffer after rendering is complete. Rendering the content is necessary because it typically changes every frame. However, if the content is static, this is unnecessary. It might make more sense to keep the rendered framebuffer instead of discarding it. If the content of the effect node is static, set the node’s shouldRasterize property to true. Setting this property causes the following changes in behavior:

  • The framebuffer is not discarded at the end of rasterization. This also means that more memory is being used by the effect node, and rendering may take slightly longer.

  • When a new frame is rendered, the framebuffer is rendered only if the contents of the effect node’s descendants have changed.

  • If the effect node has a Core Image filter, changes to its properties no longer automatically update the framebuffer. You can force it to be updated by setting the shouldRasterize property to false.

You can use effect nodes to cache static content even when you aren’t applying a filter to the rendered image. This technique can be useful when the contents of a subtree are static and expensive to render.

Topics

Enabling Filter Effects

var shouldEnableEffects: Bool

A Boolean value that determines whether the effect node applies the filter to its children as they are drawn.

Configuring the Filter

var filter: CIFilter?

The Core Image filter to apply.

var shouldCenterFilter: Bool

A Boolean value that determines whether the effect node automatically sets the filter’s image center.

Blending the Results to the Framebuffer

var blendMode: SKBlendMode

The blend mode used to draw the filtered image into the parent’s framebuffer.

Working with Custom Shaders

var shader: SKShader?

A custom shader that is called when the effect node is blended into the parent’s framebuffer.

var attributeValues: [String : SKAttributeValue]

The values of each attribute associated with the node's attached shader.

func setValue(SKAttributeValue, forAttribute: String)

Sets an attribute value for an attached shader.

func value(forAttributeNamed: String)

The value of a shader attribute.

Caching the Filter Results

var shouldRasterize: Bool

A Boolean value that indicates whether the results of rendering the child nodes should be cached.

See Also

Integrating with Other Frameworks

class SK3DNode

A node that renders a Scene Kit scene as a 2D image.