效果

什么是 Direct2D 效果?

可以使用 Direct2D 将一个或多个高质量的效果应用于图像或一组图像。 效果 API 基于 Direct3D 11 构建,并利用 GPU 功能进行图像处理。 可以在效果图中链接效果,并组合或混合效果的输出。

Direct2D 效果执行图像处理任务,例如更改亮度、解除图像饱和或创建投影。 效果可以接受零个或多个输入图像,公开多个控制其操作的属性,并生成单个输出图像。

每个效果创建由单个转换组成的内部转换图。 每个转换表示单个图像操作。 转换的主要目的是容纳为每个输出像素执行的着色器。 这些着色器可以包括像素着色器、顶点着色器、GPU 的混合阶段和计算着色器。

Direct2Dbuilt-in 效果和自定义效果都可以这样使用自定义效果 API

有一系列 内置效果 ,如此处的类别。 有关完整列表,请参阅 “内置效果” 部分。

可以将效果应用于任何位图,包括:Windows映像组件加载的图像 (WIC) Direct2D 绘制的基元、DirectWrite的文本或 Direct3D 呈现的场景。

借助 Direct2D 效果,可以编写可用于应用程序的效果。 使用自定义效果框架,可以使用 GPU 功能,例如像素着色器、顶点着色器以及混合单元。 还可以在自定义效果中包含其他内置效果或自定义效果。 用于生成自定义效果的框架与用于创建 Direct2D 内置效果的框架相同。 Direct2D 效果作者 API 提供了一组用于创建和注册效果的接口。

更多效果主题

本主题的其余部分介绍了 Direct2D 效果的基础知识,例如对图像应用效果。 此处的表包含有关效果的其他主题的链接。

主题 说明
效果着色器链接
Direct2D 使用称为效果着色器链接的优化,该链接将多个效果图呈现传递到单个传递中。
自定义效果
演示如何使用标准 HLSL 编写自己的自定义效果。
如何使用 FilePicker 将图像加载到 Direct2D 效果中
演示如何使用 Windows::存储::P ickers::FileOpenPicker 将图像加载到 Direct2D 效果中。
如何将 Direct2D 内容保存到图像文件
本主题演示如何使用 IWICImageEncoderID2D1Image 形式的内容保存到编码的图像文件(如 JPEG)。
如何将效果应用于基元
本主题演示如何将一系列效果应用于 Direct2DDirectWrite基元。
控制效果图中的精度和数值剪辑
使用 Direct2D 呈现效果的应用程序必须注意实现与数值精度相关的所需质量和可预测性级别。

将效果应用于图像

可以使用 Direct2D 效果 API 将转换应用到图像。

注意

此示例假定已创建 ID2D1DeviceContextIWICBitmapSource 对象。 有关创建这些对象的详细信息,请参阅如何使用 FilePicker 和设备上下文将图像加载到 Direct2D 效果中。

  1. 声明 ID2D1Effect 变量,然后使用 ID2DDeviceContext::CreateEffect 方法创建位图源效果。

        ComPtr<ID2D1Effect> bitmapSourceEffect;
    
        DX::ThrowIfFailed(m_d2dContext->CreateEffect(CLSID_D2D1BitmapSource, &bitmapSourceEffect));
    
  2. 使用 ID2D1Effect::SetValue 将 BitmapSource 属性设置为 WIC 位图源。

            DX::ThrowIfFailed(m_bitmapSourceEffect->SetValue(D2D1_BITMAPSOURCE_PROP_WIC_BITMAP_SOURCE, m_wicBitmapSource.Get()));
    
  3. 声明 ID2D1Effect 变量,然后创建 高斯模糊 效果。

        ComPtr<ID2D1Effect> gaussianBlurEffect;
    
        DX::ThrowIfFailed(m_d2dContext->CreateEffect(CLSID_D2D1GaussianBlur, &gaussianBlurEffect));
    
  4. 设置输入以从位图源效果接收图像。 设置 SetValue 方法和标准偏差属性的模糊量。

        gaussianBlurEffect->SetInputEffect(0, bitmapSourceEffect.Get());
    
        DX::ThrowIfFailed(gaussianBlurEffect->SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, 6.0f));
    
  5. 使用设备上下文绘制生成的图像输出。

        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();
    

    必须在 ID2DDeviceContext::BeginDrawEndDraw 调用之间调用 DrawImage 方法,就像其他 Direct2D 呈现操作一样。 DrawImage 可以拍摄图像或效果的输出,并将其呈现到目标图面。

空间转换

Direct2D 提供内置效果,可以转换 2D 和 3D 空间中的图像以及缩放。 缩放和转换效果提供各种质量级别,例如:最近的邻居、线性、立方体、多样本线性、异质和高质量的立方体。

注意

但是,如果在缩放时将 缓存 属性设置为 true,则当缩放时,异性模式会生成 mipmap,但每次对于足够小的图像,输入到转换的效果上不会生成 mipmap。

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();

这种使用 2D 相交转换效果会稍微旋转位图反时针。

之前
2d affine effect before image.
之后
2d affine effect after image.

组合图像

某些效果接受多个输入,并将其组合成一个生成的图像。

内置复合和算术复合效果提供各种模式,有关详细信息,请参阅 复合 主题。 混合效果有多种可用的 GPU 加速模式。

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();

复合效果根据指定的模式以不同的方式组合图像。

像素调整

有几个内置 Direct2D 效果可用于更改像素数据。 例如,颜色矩阵效果可用于更改图像的颜色。

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();

此代码采用图像并更改颜色,如此处的示例图像所示。

之前
color matrix effect before image.
之后
color matrix effect after image.

有关详细信息,请参阅 颜色内置效果 部分。

生成效果图

可以将效果链接在一起以转换图像。 例如,此处的代码应用阴影和二维转换,然后将结果组合在一起。

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();

下面是结果。

shadow effect output.

效果将 ID2D1Image 对象作为输入。 可以使用 ID2D1Bitmap ,因为接口派生自 ID2D1Image。 还可以使用 ID2D1Effect::GetOutput 获取 ID2D1Effect 对象的输出作为 ID2D1Image 或使用 SetInputEffect 方法,该方法可转换输出。 在大多数情况下,效果图由直接链接在一起的 ID2D1Effect 对象组成,这样可以轻松地将多个效果应用于图像以创建引人注目的视觉对象。

有关详细信息,请参阅 如何将效果应用于基元

Direct2D 基本图像效果示例

内置效果