Introduction to Direct2D Effects

[This documentation is preliminary and is subject to change.]

You can use the Direct2D Effects API to process images using GPU accelerated effects and develop your own effects. It also provides interoperation with other parts of Direct2D, DirectWrite, Windows Imaging Component (WIC) and Direct3D.

This topic contains:

  • About Direct2D Effects
  • Built-in effects
  • Custom effects
  • Effects on Direct2D primitives and text
  • Related topics

About Direct2D Effects

You can use Direct2D Effects to apply one or more high quality effects to an image or a set of images. The effects APIs are built on Direct3D 11 and take advantage of GPU features for image processing. You can chain effects in an effect graph and compose or blend the output of effects.

An effect encapsulates one or more image operations as a single Direct2D Effect operation. These operations can include the use of pixel shaders, vertex shaders, the blend stage of a GPU, and compute shaders. A Direct2D Effect can also include other Direct2D Effects in addition to other operations. These type of operations make up the Direct2D built-in effects and you can use them to make custom effects using the Effect Author API.

You can apply effects to images loaded by the Windows Imaging Component (WIC), primitives drawn by Direct2D, text from DirectWrite, or scenes rendered by Direct3D.

To modify effect behavior you set the properties of the effect. Effects have two types of properties: a set of read-only properties that are common to all effects, such as the Display Name or Description properties and properties that are specific to a certain effect, such as the standard deviation of a blur or the direction and strength of a lighting effect. You can enumerate these additional properties and set them to modify the effect output. Each property has a default value, so you don't need to set a property explicitly if the default works for you.

Effect take ID2D1Image objects as input. You can use an ID2D1Bitmap or an ID2D1Effect because both interfaces are derived from ID2D1Image. In most cases an effect graph consists of ID2D1Effect objects directly chained together, which makes it easy to apply multiple effects to an image to create compelling visuals.

Effects are not processed until the effect is drawn, so you can change the properties to all the effects before processing the effect graph to render the image. This way you can animate properties and the device context doesn't perform any unnecessary work. The effects that don't need to be processed are optimized to remain unprocessed.

Additionally, the Direct2D processes only the pixels that it needs for the final result. Each effect processes only the portion of the image required by the effects in the image graph that consume the output. Direct2D, automatically handles images that are larger than the GPU texture size and manages memory for effect operations.

Built-in effects

Direct2D includes a range of built-in effects from categories like the ones here. See the Built-in Effects topic for a full categorized list with example images.

The figure here shows an example of an image before and after the Gaussian Blur effect has been applied to it.

Image before and after the Gaussian Blur effect.

Effects can have zero or more inputs and zero or one output, the built-in effects here are a few examples.

  • Effects that take in a single image and output a single, processed image such as a blur, crop, or scale effect.
  • Composite effects that combine multiple images into a single output.
  • Source effects that have no image input, but produce an image programmatically, like the turbulence effect, or load an image from storage using a IWICBitmapSource, like the bitmap source effect.
  • Analysis effects that take in an image and output information about the image. Typically, these effects return information via properties. They can also output images. They are typically implemented using DirectCompute.

A number of Built-in effects are included. Some examples are: 3D Perspective Transform, Gaussian Blur, Composite and Blend, Specular Lighting, Diffuse Lighting, and Histogram.

For more info and a full list, see Built-in Effects.

Custom effects

With Direct2D Effects you can write your own effects that you can use for your applications. A custom effect framework allows you to use GPU features such as pixel shaders, vertex shaders, and the blending unit. You can also include other built-in or custom effects in your custom effect. The framework for building custom effects is the same one that was used to create the built-in effects of Direct2D. The Direct2D effect author API provides a set of interfaces to create and register effects.

When you create a custom effect and then register it with Direct2D Effects, you can enumerate the effect and add it to effect graphs the same as built-in effects. You use the ID2D1Factory1::RegisterEffect to pass on the registration information about a custom effect and its properties to Direct2D.

Effects on Direct2D primitives and text

You can use the Direct2D Effects API to apply effect graphs to primitives rendered by Direct2D to an image. The example here has two rounded rectangles and the text "Direct2D". Use Direct2D to draw the rectangles and DirectWrite to draw the text.

Rectangles with the text "Direct2D" within.

Using Direct2D Effects, you can make this image look like the next image. Apply the Gaussian Blur, Point Specular Lighting, Arithmetic Composite, and Composite effects to the 2D primitives to create the image here.

Rectangles with the text "Direct2D" within after several effects are applied.

After you render the rectangles and text to a intermediate surface, you can use this as input for ID2D1Effect objects in the image graph.

In this example, set the original image as the input to the Gaussian Blur effect and then set the output of the blur as the input for the Point Specular Lighting effect. The result of this effect is then composited with the original image twice to get the final image that is rendered to the window.

Here is a diagram of the image graph.

Effect graph diagram.

This effect graph consists of four ID2D1Effect objects, each representing a different built-in effect. You can create and connect custom effects in the same way, after you register them using ID1D1Factory1::RegisterEffect. The code here creates the effects, sets the properties, and connects the effect graph shown earlier.

  1. Create the Gaussian blur effect using the ID2D1DeviceContext::CreateEffect method and specifying the proper CLSID. The CLSIDs for the built-in effects are defined in d2d1effects.h. You then set the standard deviation of the blur using the ID2D1Effect::SetValue method.

    // Create the Gaussian Blur Effect
    DX::ThrowIfFailed(
        m_d2dContext->CreateEffect(CLSID_D2D1GaussianBlur, &gaussianBlurEffect)
        );
    
    // Set the blur amount
    DX::ThrowIfFailed(
        gaussianBlurEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, sc_gaussianBlurStDev)
        );
    

    The Gaussian blur effect blurs all of the channels of the image, including the alpha channel.

  2. Create the specular lighting effect and set the properties. The position of the light is a vector of 3 floating point values, so you must declare it as a separate variable and pass it to the SetValue method.

    // Create the Specular Lighting Effect
    DX::ThrowIfFailed(
        m_d2dContext->CreateEffect(CLSID_D2D1PointSpecular, &specularLightingEffect)
        );
    
    DX::ThrowIfFailed(
        specularLightingEffect->SetValue(D2D1_POINTSPECULAR_PROP_LIGHT_POSITION, sc_specularLightPosition)
        );
    
    DX::ThrowIfFailed(
        specularLightingEffect->SetValue(D2D1_POINTSPECULAR_PROP_SPECULAR_EXPONENT, sc_specularExponent)
        );
    
    DX::ThrowIfFailed(
        specularLightingEffect->SetValue(D2D1_POINTSPECULAR_PROP_SURFACE_SCALE, sc_specularSurfaceScale)
        );
    
    DX::ThrowIfFailed(
        specularLightingEffect->SetValue(D2D1_POINTSPECULAR_PROP_SPECULAR_CONSTANT, sc_specularConstant)
        );
    

    The specular lighting effect uses the alpha channel of the input to create a height map for the lighting.

  3. There are two different composite effects that you can use the composite effect and the arithmetic composite. This effect graph uses both.

    Create the composite effect and set the mode to D2D1_COMPOSITE_MODE_SOURCE_IN, which outputs the intersection of the source and destination images.

    The arithmetic composite effect composes the two input images based on a formula defined by the World Wide Web Consortium (W3C) for the Scalable Vector Graphics (SVG) standard. Create arithmetic composite and set the coefficients for the formula.

    // Create the Composite Effects
    DX::ThrowIfFailed(
        m_d2dContext->CreateEffect(CLSID_D2D1Composite, &compositeEffect)
        );
    
    DX::ThrowIfFailed(
        compositeEffect->SetValue(D2D1_COMPOSITE_PROP_MODE, D2D1_COMPOSITE_MODE_SOURCE_IN)
        );
    
    DX::ThrowIfFailed(
        m_d2dContext->CreateEffect(CLSID_D2D1ArithmeticComposite, &m_arithmeticCompositeEffect)
        );
    
    DX::ThrowIfFailed(
        m_arithmeticCompositeEffect->SetValue(D2D1_ARITHMETICCOMPOSITE_PROP_COEFFICIENTS, sc_arithmeticCoefficients)
        );
    

    The coefficients for the arithmetic composite effect are shown here.

    D2D1_VECTOR_4F sc_arithmeticCoefficients   = D2D1::Vector4F(0.0f, 1.0f, 1.0f, 0.0f);
    

    In this effect graph, both of the composite effects take the output of the other effects and the intermediate surface as inputs and composites them.

  4. Finally, you connect the effects to form the graph by setting the inputs to the proper images and bitmaps.

    The first effect, Gaussian blur, receives its input from the intermediate surface that you rendered the primitives to. You set the input using the ID2D1Effect::SetInput method and specifying the index of an ID2D1Image object. The Gaussian blur and specular lighting effects have only a single input. The specular lighting effect uses the blurred alpha channel of the Gaussian blur

    The composite and arithmetic composite effects have multiple inputs. To make sure the images are put together in the right order, you must specify the correct index for each input image.

    // Connect the graph.
    // Apply a blur effect to the original image.
    gaussianBlurEffect->SetInput(0, m_inputImage.Get());
    
    // Apply a specular lighting effect to the result.
    specularLightingEffect->SetInputEffect(0, gaussianBlurEffect.Get());
    
    // Compose the original bitmap under the output from lighting and blur.
    compositeEffect->SetInput(0, m_inputImage.Get());
    compositeEffect->SetInputEffect(1, specularLightingEffect.Get());
    
    // Compose the original bitmap under the output from lighting and blur.
    m_arithmeticCompositeEffect->SetInput(0, m_inputImage.Get());
    m_arithmeticCompositeEffect->SetInputEffect(1, compositeEffect.Get());
    
  5. Pass the arithmetic composite effect object into the ID2DDeviceContext::DrawImage method and it processes and draws the output of the graph.

        // Draw the output of the effects graph.
        m_d2dContext->DrawImage(
            m_arithmeticCompositeEffect.Get(),
            D2D1::Point2F(
                (size.width - sc_inputBitmapSize.width) / 2,
                (size.height - sc_inputBitmapSize.height) / 2 + sc_offset
                )
            );
    

Direct2D Built-in Effects

HLSL

 

 

Build date: 3/7/2012