不透明蒙板概述

本主题介绍如何使用位图和画笔定义不透明度掩码。 其中包含以下各节。

先决条件

本概述假定你熟悉基本的 Direct2D 绘图操作,如 创建简单的 Direct2D 应用程序 演练中所述。 还应熟悉不同类型的画笔,如 画笔概述中所述。

什么是不透明度掩码?

不透明蒙板是由画笔或位图描述的掩码,应用于另一个对象,使该对象部分或完全透明。 不透明度掩码使用 alpha 通道信息来指定如何将对象的源像素混合到最终目标中。 掩码的透明部分指示隐藏基础图像的区域,而掩码的不透明部分指示掩码对象可见的位置。

可通过多种方式应用不透明掩码:

  • 使用 ID2D1RenderTarget::FillOpacityMask 方法。 FillOpacityMask 方法绘制呈现目标的矩形区域,然后应用由位图定义的不透明蒙板。 当不透明度掩码是位图并且想要填充矩形区域时,请使用此方法。
  • 使用 ID2D1RenderTarget::FillGeometry 方法。 FillGeometry 方法使用指定的 ID2D1BitmapBrush 绘制几何图形的内部,然后应用由画笔定义的不透明度蒙板。 如果要将不透明度蒙板应用于几何图形,或者想要使用画笔作为不透明度掩码,请使用此方法。
  • 使用 ID2D1Layer 应用不透明掩码。 如果要对一组绘图内容(而不仅仅是单个形状或图像)应用不透明蒙板,请使用此方法。 有关详细信息,请参阅 层概述

使用 FillOpacityMask 方法将位图用作不透明度掩码

FillOpacityMask 方法绘制呈现目标的矩形区域,然后应用由 ID2D1Bitmap 定义的不透明度掩码。 如果位图要用作矩形区域的不透明度掩码,请使用此方法。

下图显示了将不透明度掩码 (ID2D1Bitmap 与花) 图像应用于 ID2D1BitmapBrush 的效果,该图像为具有植物图像的 ID2D1BitmapBrush 。 生成的图像是剪裁成花形的植物位图。

在植物图片上用作不透明蒙板的花位图

以下代码示例演示如何完成此操作。

第一个示例加载以下位图 (m_pBitmapMask)以用作位图掩码。 下图显示了生成的输出。 请注意,尽管位图的不透明部分显示为黑色,但位图中的颜色信息对不透明蒙板没有影响:仅使用位图中每个像素的不透明度信息。 此位图中完全不透明的像素已着色为黑色,仅用于说明目的。

花位图掩码的插图

在此示例中, ID2D1Bitmap 由示例中其他位置定义的帮助程序方法 LoadResourceBitmap 加载。

            if (SUCCEEDED(hr))
            {
                hr = LoadResourceBitmap(
                    m_pRenderTarget,
                    m_pWICFactory,
                    L"BitmapMask",
                    L"Image",
                    &m_pBitmapMask
                    );
            }

下一个示例定义应用不透明度掩码的画笔 (m_pFernBitmapBrush)。 此示例使用包含 fern 图像的 ID2D1BitmapBrush ,但可以改用 ID2D1SolidColorBrushID2D1LinearGradientBrushID2D1RadialGradientBrush 。 下图显示了生成的输出。

位图画笔使用的位图

            if (SUCCEEDED(hr))
            {
                D2D1_BITMAP_BRUSH_PROPERTIES propertiesXClampYClamp = 
                    D2D1::BitmapBrushProperties(
                    D2D1_EXTEND_MODE_CLAMP,
                    D2D1_EXTEND_MODE_CLAMP,
                    D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
                    );
                hr = m_pRenderTarget->CreateBitmapBrush(
                    m_pFernBitmap,
                    propertiesXClampYClamp,
                    &m_pFernBitmapBrush
                    );


            }

定义不透明度掩码和画笔后,可以在应用程序的呈现方法中使用 FillOpacityMask 方法。 调用 FillOpacityMask 方法时,必须指定所使用的不透明度掩码的类型: D2D1_OPACITY_MASK_CONTENT_GRAPHICSD2D1_OPACITY_MASK_CONTENT_TEXT_NATURALD2D1_OPACITY_MASK_CONTENT_TEXT_GDI_COMPATIBLE。 有关这三种类型的含义,请参阅 D2D1_OPACITY_MASK_CONTENT

注意

从Windows 8开始,不需要D2D1_OPACITY_MASK_CONTENT。 请参阅 ID2D1DeviceContext::FillOpacityMask 方法,该方法没有 D2D1_OPACITY_MASK_CONTENT 参数。

 

下一个示例将呈现目标的抗锯齿模式设置为 D2D1_ANTIALIAS_MODE_ALIASED ,以便不透明度掩码正常工作。 然后,它调用 FillOpacityMask 方法,并向其传递不透明度掩码 (m_pBitmapMask) 、不透明蒙板 (m_pFernBitmapBrush) 应用于的画笔、不透明度掩码中的内容类型 (D2D1_OPACITY_MASK_CONTENT_GRAPHICS) 以及要绘制的区域。 下图显示了生成的输出。

应用了不透明蒙板的植物图片的插图

        D2D1_RECT_F rcBrushRect = D2D1::RectF(5, 5, 155, 155);


        // D2D1_ANTIALIAS_MODE_ALIASED must be set for FillOpacityMask to function properly
        m_pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
        m_pRenderTarget->FillOpacityMask(
            m_pBitmapMask,
            m_pFernBitmapBrush,
            D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
            &rcBrushRect
            );
        m_pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);

此示例中已省略代码。

使用 FillGeometry 方法将画笔用作不透明度蒙板

上一部分介绍了如何将 ID2D1Bitmap 用作不透明掩码。 Direct2D 还提供 ID2D1RenderTarget::FillGeometry 方法,使你可以在填充 ID2D1Geometry 时选择性地将画笔指定为不透明蒙板。 这使你可以使用 ID2D1LinearGradientBrush 或 ID2D1RadialGradientBrush) 和位图从渐变 ( (使用 ID2D1Bitmap) 创建不透明度掩码。

FillGeometry 方法采用三个参数:

以下部分介绍如何使用 ID2D1LinearGradientBrushID2D1RadialGradientBrush 对象作为不透明掩码。

使用线性渐变画笔作为不透明度蒙板

下图显示了将线性渐变画笔应用于填充了花卉位图的矩形的效果。

应用了线性渐变画笔的花卉位图

后续步骤介绍了如何重新创建此效果。

  1. 定义要屏蔽的内容。 以下示例创建 ID2D1BitmapBrush,m_pLinearFadeFlowersBitmapm_pLinearFadeFlowersBitmap的扩展模式 x 和 y- 设置为 D2D1_EXTEND_MODE_CLAMP,以便可以通过 FillGeometry 方法将其与不透明度掩码一起使用。

    if (SUCCEEDED(hr))
    {
        // Create the bitmap to be used by the bitmap brush.
        hr = LoadResourceBitmap(
            m_pRenderTarget,
            m_pWICFactory,
            L"LinearFadeFlowers",
            L"Image",
            &m_pLinearFadeFlowersBitmap
            );
    }
    
    if (SUCCEEDED(hr))
        {
            D2D1_BITMAP_BRUSH_PROPERTIES propertiesXClampYClamp = 
                D2D1::BitmapBrushProperties(
                D2D1_EXTEND_MODE_CLAMP,
                D2D1_EXTEND_MODE_CLAMP,
                D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
                );
    
    C++
                    if (SUCCEEDED(hr))
                    {
                        hr = m_pRenderTarget->CreateBitmapBrush(
                            m_pLinearFadeFlowersBitmap,
                            propertiesXClampYClamp,
                            &m_pLinearFadeFlowersBitmapBrush
                            );
                    }
    C++
                }
  2. 定义不透明度掩码。 下一个代码示例创建一个对角线线性渐变画笔, (m_pLinearGradientBrush) ,该画笔从位置 0 处的完全不透明黑色淡化到位置 1 处完全透明的白色。

                if (SUCCEEDED(hr))
                {
                    ID2D1GradientStopCollection *pGradientStops = NULL;

                    static const D2D1_GRADIENT_STOP gradientStops[] =
                    {
                        {   0.f,  D2D1::ColorF(D2D1::ColorF::Black, 1.0f)  },
                        {   1.f,  D2D1::ColorF(D2D1::ColorF::White, 0.0f)  },
                    };

                    hr = m_pRenderTarget->CreateGradientStopCollection(
                        gradientStops,
                        2,
                        &pGradientStops);


                    if (SUCCEEDED(hr))
                    {
                        hr = m_pRenderTarget->CreateLinearGradientBrush(
                            D2D1::LinearGradientBrushProperties(
                                D2D1::Point2F(0, 0),
                                D2D1::Point2F(150, 150)),
                            pGradientStops,
                            &m_pLinearGradientBrush);
                    }

    
                pGradientStops->Release();
                }
  1. 使用 FillGeometry 方法。 最后一个示例使用 FillGeometry 方法对内容画笔使用 ID2D1BitmapBrush (m_pLinearFadeFlowersBitmap) 填充 ID2D1RectangleGeometry (m_pRectGeo) ,并应用不透明度掩码 (m_pLinearGradientBrush) 。
            m_pRenderTarget->FillGeometry(
                m_pRectGeo, 
                m_pLinearFadeFlowersBitmapBrush, 
                m_pLinearGradientBrush
                );

此示例中已省略代码。

使用径向渐变画笔作为不透明度蒙板

下图显示了将径向渐变画笔应用于填充了叶子位图的矩形的视觉效果。

应用径向渐变画笔的叶状位图

第一个示例创建 ID2D1BitmapBrush,m_pRadialFadeFlowersBitmapBrush。 为便于 FillGeometry 方法将其与不透明度掩码一起使用 ,m_pRadialFadeFlowersBitmapBrush的 扩展模式 x 和 y- 设置为 D2D1_EXTEND_MODE_CLAMP

            if (SUCCEEDED(hr))
            {
                // Create the bitmap to be used by the bitmap brush.
                hr = LoadResourceBitmap(
                    m_pRenderTarget,
                    m_pWICFactory,
                    L"RadialFadeFlowers",
                    L"Image",
                    &m_pRadialFadeFlowersBitmap
                    );
            }


            if (SUCCEEDED(hr))
            {
                D2D1_BITMAP_BRUSH_PROPERTIES propertiesXClampYClamp = 
                    D2D1::BitmapBrushProperties(
                    D2D1_EXTEND_MODE_CLAMP,
                    D2D1_EXTEND_MODE_CLAMP,
                    D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
                    );
C++
                if (SUCCEEDED(hr))
                {
                    hr = m_pRenderTarget->CreateBitmapBrush(
                        m_pLinearFadeFlowersBitmap,
                        propertiesXClampYClamp,
                        &m_pLinearFadeFlowersBitmapBrush
                        );
                }
C++
            }

下一个示例定义将用作不透明度掩码的径向渐变画笔。

            if (SUCCEEDED(hr))
            {
                ID2D1GradientStopCollection *pGradientStops = NULL;

                static const D2D1_GRADIENT_STOP gradientStops[] =
                {
                    {   0.f,  D2D1::ColorF(D2D1::ColorF::Black, 1.0f)  },
                    {   1.f,  D2D1::ColorF(D2D1::ColorF::White, 0.0f)  },
                };

                hr = m_pRenderTarget->CreateGradientStopCollection(
                    gradientStops,
                    2,
                    &pGradientStops);




                if (SUCCEEDED(hr))
                {
                    hr = m_pRenderTarget->CreateRadialGradientBrush(
                        D2D1::RadialGradientBrushProperties(
                            D2D1::Point2F(75, 75),
                            D2D1::Point2F(0, 0),
                            75,
                            75),
                        pGradientStops,
                        &m_pRadialGradientBrush);
                }
                pGradientStops->Release();
            }

最后的代码示例使用 ID2D1BitmapBrush (m_pRadialFadeFlowersBitmapBrush) 和不透明度掩码 (m_pRadialGradientBrush) 填充 ID2D1RectangleGeometry (m_pRectGeo) 。

        m_pRenderTarget->FillGeometry(
            m_pRectGeo,
            m_pRadialFadeFlowersBitmapBrush, 
            m_pRadialGradientBrush
            );

此示例中已省略代码。

将不透明度掩码应用于层

调用 PushLayerID2D1Layer 推送到呈现器目标时,可以使用 D2D1_LAYER_PARAMETERS 结构将画笔应用为不透明度掩码。 下面的代码示例使用 ID2D1RadialGradientBrush 作为不透明掩码。

HRESULT DemoApp::RenderWithLayerWithOpacityMask(ID2D1RenderTarget *pRT)
{   

    HRESULT hr = S_OK;

    // Create a layer.
    ID2D1Layer *pLayer = NULL;
    hr = pRT->CreateLayer(NULL, &pLayer);

    if (SUCCEEDED(hr))
    {
        pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 250));

        // Push the layer with the content bounds.
        pRT->PushLayer(
            D2D1::LayerParameters(
                D2D1::InfiniteRect(),
                NULL,
                D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
                D2D1::IdentityMatrix(),
                1.0,
                m_pRadialGradientBrush,
                D2D1_LAYER_OPTIONS_NONE),
            pLayer
            );

        pRT->DrawBitmap(m_pBambooBitmap, D2D1::RectF(0, 0, 190, 127));

        pRT->FillRectangle(
            D2D1::RectF(25.f, 25.f, 50.f, 50.f), 
            m_pSolidColorBrush
            );
        pRT->FillRectangle(
            D2D1::RectF(50.f, 50.f, 75.f, 75.f),
            m_pSolidColorBrush
            ); 
        pRT->FillRectangle(
            D2D1::RectF(75.f, 75.f, 100.f, 100.f),
            m_pSolidColorBrush
            );    
 
        pRT->PopLayer();
    }
    SafeRelease(&pLayer);
   
    return hr;
    
}

有关使用层的详细信息,请参阅 层概述

画笔概述

层概述