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
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.
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.
The figure here shows an example of an image before and after the Gaussian Blur effect has been applied to it.
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.
For more info and a full list, see Built-in 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.
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.
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.
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.
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.
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.
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.
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.
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.
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
// 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());
Build date: 3/7/2012