效果

什么是 Direct2D 效果?

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

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

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

Direct2D 内置效果和自定义效果都可以使用 自定义效果 API 以这种方式工作。

有一系列 内置效果,如这里的类别。 有关完整列表,请参阅内置效果部分。

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

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

更多效果主题

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

主题 说明
效果着色器链接
Direct2D 使用一种称为效果着色器链接的优化,将多个效果图渲染通道合并为一个通道。
自定义效果
演示如何使用标准 HLSL 编写自己的自定义效果。
如何使用 FilePicker 将图像加载到 Direct2D 效果中
演示如何使用 Windows::Storage::Pickers::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();
    

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

空间变换

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

注意

各向异性模式在缩放时生成 mipmap,但是如果在输入到转换的效果上将 Cached 属性设置为 true,则在图像足够小的情况下,不会每次都生成 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 相交效果。
之后
图像后的 2d 仿效效果。

合成图像

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

内置的复合和算术复合效果提供了各种模式,有关详细信息,请参阅 复合主题。 混合效果具有多种可用的 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();

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

之前
图像前的颜色矩阵效果。
之后
图像后的颜色矩阵效果。

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

生成效果图

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

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

结果如下。

阴影效果输出。

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

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

Direct2D 基础图像效果示例

内置效果