Effects

What are Direct2D effects?

You can use Direct2D 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.

A Direct2D effect performs an imaging task, like changing brightness, de-saturating an image, or creating a drop shadow. Effects can accept zero or more input images, expose multiple properties that control their operation, and generate a single output image.

Each effect creates an internal transform graph made up of individual transforms. Each transform represents a single image operation. The main purpose of a transform is to house the shaders that are executed for each output pixel. These shaders can include pixel shaders, vertex shaders, the blend stage of a GPU, and compute shaders.

Both the Direct2D built-in effects and custom effects you can make using the custom effects API work this way.

There are a range of built-in effects from categories like the ones here. See the Built-in Effects section for a full list.

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

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.

More effects topics

The rest of this topic explains the basics of Direct2D effects, like applying an effect to an image. The table here has links to additional topics about effects.

Topic Description
Effect Shader Linking
Direct2D uses an optimization called effect shader linking which combines multiple effect graph rendering passes into a single pass.
Custom effects
Shows you how to write your own custom effects using standard HLSL.
How to load an image into Direct2D Effects using the FilePicker
Shows how to use the Windows::Storage::Pickers::FileOpenPicker to load an image into Direct2D effects.
How to save Direct2D content to an image file
This topic shows how to use IWICImageEncoder to save content in the form of an ID2D1Image to an encoded image file such as JPEG.
How to Apply Effects to Primitives
This topic shows how to apply a series of effect to Direct2D and DirectWrite primitives.
Controlling Precision and Numerical Clipping in Effect Graphs
Applications that render effects using Direct2D must take care to achieve the desired level of quality and predictability with respect to numerical precision.

Applying an effect to an image

You can use the Direct2D effects API to apply transforms to images.

Note

This example assumes that you already have ID2D1DeviceContext and IWICBitmapSource objects created. For more information on creating these objects see How to load an image into Direct2D effects using the FilePicker and Devices and Device Contexts.

  1. Declare an ID2D1Effect variable and then create a bitmap source effect using the ID2DDeviceContext::CreateEffect method.

        ComPtr<ID2D1Effect> bitmapSourceEffect;
    
        DX::ThrowIfFailed(m_d2dContext->CreateEffect(CLSID_D2D1BitmapSource, &bitmapSourceEffect));
    
  2. Set the BitmapSource property to the WIC bitmap source using the ID2D1Effect::SetValue.

            DX::ThrowIfFailed(m_bitmapSourceEffect->SetValue(D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE, m_wicBitmapSource.Get()));
    
  3. Declare an ID2D1Effect variable and then create the gaussian blur effect.

        ComPtr<ID2D1Effect> gaussianBlurEffect;
    
        DX::ThrowIfFailed(m_d2dContext->CreateEffect(CLSID_D2D1GaussianBlur, &gaussianBlurEffect));
    
  4. Set the input to receive the image from the bitmap source effect. Set the blur amount the SetValue method and the standard deviation property.

        gaussianBlurEffect->SetInputEffect(0, bitmapSourceEffect.Get());
    
        DX::ThrowIfFailed(gaussianBlurEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, 6.0f));
    
  5. Use the device context to draw the resulting image output.

        m_d2dContext->BeginDraw();
    
        m_d2dContext->Clear(D2D1::ColorF(D2D1::ColorF::CornflowerBlue));
    
        // Draw the blurred image.
        m_d2dContext->DrawImage(gaussianBlurEffect.Get());
    
        HRESULT hr = m_d2dContext->EndDraw();
    

    The DrawImage method must be called between the ID2DDeviceContext::BeginDraw and EndDraw calls like other Direct2D render operations. DrawImage can take an image or the output of an effect and render it to the target surface.

Spatial Transforms

Direct2D provides built-in effects that can transform images in 2D and 3D space, as well as scaling. The scale and transform effects offer various quality levels like: nearest neighbor, linear, cubic, multi-sample linear, anisotropic, and high quality cubic.

Note

Anisotropic mode generates mipmaps when scaling, however, if you set the Cached property to true on the effects that are input to the transform the mipmaps won't be generated every time for sufficiently small images.

ComPtr<ID2D1Effect> affineTransformEffect;
DX::ThrowIfFailed(m_d2dContext->CreateEffect(CLSID_D2D12DAffineTransform, &affineTransformEffect));

affineTransformEffect->SetInput(0, bitmap.Get());

D2D1_MATRIX_3X2_F matrix = D2D1::Matrix3x2F(0.9f, -0.1f,  0.1f, 0.9f, 8.0f, 45.0f);
DX::ThrowIfFailed(affineTransformEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX, matrix));

m_d2dContext->BeginDraw();
m_d2dContext->DrawImage(affineTransformEffect.Get());
m_d2dContext->EndDraw();

This use of the 2D affine transform effect rotates the bitmap counterclockwise slightly.

Before
2d affine effect before image.
After
2d affine effect after image.

Compositing images

Some effects accept multiple inputs and composite them into one resulting image.

The built-in composite and arithmetic composite effects provide various modes, for more info see the composite topic. The blend effect has a variety of GPU accelerated modes available.

ComPtr<ID2D1Effect> compositeEffect;
DX::ThrowIfFailed(m_d2dContext->CreateEffect(CLSID_D2D1Composite, &compositeEffect));

compositeEffect->SetInput(0, bitmap.Get());
compositeEffect->SetInput(1, bitmapTwo.Get());

m_d2dContext->BeginDraw();
m_d2dContext->DrawImage(compositeEffect.Get());
m_d2dContext->EndDraw();

The composite effect combines images in various different ways according to the mode you specify.

Pixel adjustments

There are a few built-in Direct2D effects that allow you to alter the pixel data. For example, the color matrix effect can be used to change the color of an image.

ComPtr<ID2D1Effect> colorMatrixEffect;
DX::ThrowIfFailed(m_d2dContext->CreateEffect(CLSID_D2D1ColorMatrix, &colorMatrixEffect));

colorMatrixEffect->SetInput(0, bitmap.Get());

D2D1_MATRIX_5X4_F matrix = D2D1::Matrix5x4F(0, 0, 1, 0,   0, 1, 0, 0,   1, 0, 0, 0,   0, 0, 0, 1,   0, 0, 0, 0);
DX::ThrowIfFailed(colorMatrixEffect->SetValue(D2D1_COLORMATRIX_PROP_COLOR_MATRIX, matrix));

m_d2dContext->BeginDraw();
m_d2dContext->DrawImage(colorMatrixEffect.Get());
m_d2dContext->EndDraw();

This code takes the image and alters the color as shown in the example images here.

Before
color matrix effect before image.
After
color matrix effect after image.

See the color built-in effects section for more info.

Building effect graphs

You can chain effects together to transform images. For example, the code here applies a shadow and a 2D transform, then composites the results together.

ComPtr<ID2D1Effect> shadowEffect;
ComPtr<ID2D1Effect> affineTransformEffect;
ComPtr<ID2D1Effect> compositeEffect;

DX::ThrowIfFailed(m_d2dContext->CreateEffect(CLSID_D2D1Shadow, &shadowEffect));
DX::ThrowIfFailed(m_d2dContext->CreateEffect(CLSID_D2D12DAffineTransform, &affineTransformEffect));
DX::ThrowIfFailed(m_d2dContext->CreateEffect(CLSID_D2D1Composite, &compositeEffect));

shadowEffect->SetInput(0, bitmap.Get());
affineTransformEffect->SetInputEffect(0, shadowEffect.Get());

D2D1_MATRIX_3X2_F matrix = D2D1::Matrix3x2F::Translation(20, 20));

affineTransformEffect->SetValue(D2D1_2DAFFINETRANSFORM_PROP_TRANSFORM_MATRIX, matrix);

compositeEffect->SetInputEffect(0, affineTransformEffect.Get());
compositeEffect->SetInput(1, bitmap.Get());

m_d2dContext->BeginDraw();
m_d2dContext->DrawImage(compositeEffect.Get());
m_d2dContext->EndDraw();

Here is the result.

shadow effect output.

Effects take ID2D1Image objects as input. You can use an ID2D1Bitmap because the interface is derived from ID2D1Image. You can also use the ID2D1Effect::GetOutput to get the output of an ID2D1Effect object as an ID2D1Image or use the SetInputEffect method, which converts the output for you. 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.

See How to apply effects to primitives for more info.

Direct2D basic image effects sample

Built-in Effects