• Direct2D教程(十二)图层


    什么是Layers?

    Layer,中文译成图层,在Direct2D中可以用来完成一些特殊效果,使用Layer的时候,先将Layer Push到render target,然后进行绘制,此时是直接绘制在Layer上的,绘制完毕后,将Layer Pop出来,刚刚绘制在Layer上的内容就会组合到render target上。在Direct2D中,Layer使用接口ID2D1Layer来表示。

    和画刷一样,Layer由render target创建,属于设备相关的资源,Layer可以用于任何render target上,只要二者在相同的资源作用域内,在同一时间内,Layer只能用于一个render target。

    尽管Layer为创建特效提供了强大的技术支持,但是过度使用Layer将导致D2D程序性能下降,因为操作Layer是比较耗时的,比如清除Layer上的内容,将Layer上绘制的内容混合到render target上都需要时间。

    使用Layer的步骤

    在Direct2D中,使用Layer的步骤非常简单,首先创建一个Layer,在创建的时候,会指定一系列Layer的属性,在绘制之前,先将Layer Push到当前的render target上,然后进行绘制操作,绘制完毕后将Layer Pop出来即可。

    创建Layer

    创建Layer使用CreateLayer函数,该函数定义如下:

    virtual HRESULT CreateLayer(
      [in, optional]  D2D1_SIZE_F *size,
      [out]           ID2D1Layer **layer
    ) = 0;

    参数说明:

    size,这是一个矩形区域,定义了创建的Layer的大小(像素尺寸),通常这个值设置为NULL,当调用PushLayer函数时,会自动为Layer分配最小的所需尺寸(通常是render target的尺寸)。

    layer,这是一个ID2D1Layer**类型的变量,用来接收创建好的Layer。

    创建Layer代码如下。

    ID2D1Layer* g_pLayer = NULL ;
    
    // Create layer
    hr = g_pRenderTarget->CreateLayer(NULL, &g_pLayer) ;
    if (FAILED(hr))
    {
        MessageBox(hWnd, "Create layer failed!", "Error", 0) ;
        return ;
    }

    Push Layer

    在BeginDraw函数调用完之后,并且在具体绘制开始之前,将Layer Push到render target。

    PushLayer函数定义如下:

    void PushLayer(
      const D2D1_LAYER_PARAMETERS &layerParameters,
      [in]   ID2D1Layer *layer
    );

    参数说明:

    layerParameters,这是一个D2D1_LAYER_PARAMETERS类型的变量,它可以指定一系列Layer属性,D2D1_LAYER_PARAMETERS结构体定义如下:

    struct D2D1_LAYER_PARAMETERS {
      D2D1_RECT_F         contentBounds;
      ID2D1Geometry       *geometricMask;
      D2D1_ANTIALIAS_MODE maskAntialiasMode;
      D2D1_MATRIX_3X2_F   maskTransform;
      FLOAT               opacity;
      ID2D1Brush          *opacityBrush;
      D2D1_LAYER_OPTIONS  layerOptions;
    };

    参数说明

    • contentBounds,这是一个矩形区域,指定了Layer的绘制范围,也就是说在该范围之外的内容都不会被绘制。
    • geometricMask,这是一个几何图形,它指定了Layer的哪一部分被显示,比如你可以设置一Path Geometry,然后绘制一个位图,这样,只有PathGeometry内部的位图会显示,相当于给几何图形加上了位图纹理。
    • maskAntialiasMode,这个暂时用不到,不理它。
    • maskTransform,这是一个变换矩阵,指定了施加在第二个参数上的几何变换。
    • opacity,这是一个透明值,指定了Layer与render target混合时使用的透明值。
    • opacityBrush,这是一个画刷,用来改变Layer的透明值。
    • layerOptions,一个D2D1_LAYER_OPTIONS变量,基本用不到,从windows 8开始,使用D2D1_LAYER_OPTIONS1来代替。

    Direct2D提供了一个函数LayerParameters来初始化上面这些参数,这个函数为上面每个参数都提供了一个默认值,如下:

    D2D1_LAYER_PARAMETERS LayerParameters(
      _In_      const D2D1_RECT_F &contentBounds = D2D1::InfiniteRect(),
      _In_opt_  ID2D1Geometry *geometricMask = NULL,
      D2D1_ANTIALIAS_MODE maskAntialiasMode = D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
      D2D1_MATRIX_3X2_F maskTransform = D2D1::IdentityMatrix(),
      FLOAT opacity = 1.0,
      ID2D1Brush *opacityBrush = NULL,
      D2D1_LAYER_OPTIONS layerOptions = D2D1_LAYER_OPTIONS_NONE
    );

    在这里,我们使用这个函数创建一个Layer,在随后的介绍中,会指定某些特定的参数来达到特殊的效果。

    g_pRenderTarget->PushLayer(
        D2D1::LayerParameters(),
        g_pLayer
    ) ;

    绘制

    这里可以绘制任意内容,几何图形,文本,图片等,为了演示Layer的特殊效果,这里通常绘制位图。

    Pop Layer

    绘制完毕后,将Layer Pop出来,这样已经在Layer上绘制的内容就会与render target上的内容混合。

    Demo

    下面几个Demo都是通过位图来演示的,原始的位图如下,三个可爱的企鹅。

    限定位图绘制区域

    在PushLayer的时候指定一个矩形区域,在这个区域内的图形将被显示,而这个区域外的图形都将被屏蔽掉,为了方便查看结果,这里绘制一个位图,可以清楚的看到位图的那一部分被绘制了。

    代码

    g_pRenderTarget->BeginDraw() ;
    
    g_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
    
    g_pRenderTarget->PushLayer(
        D2D1::LayerParameters(D2D1::RectF(100, 100, 400, 400)),
        g_pLayer
    ) ;
    
    D2D1_SIZE_F size = g_pBitmap->GetSize() ;
    D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f) ;
    
    // Draw bitmap
    g_pRenderTarget->DrawBitmap(
        g_pBitmap,
        D2D1::RectF(
        upperLeftCorner.x,
        upperLeftCorner.y,
        upperLeftCorner.x + size.width,
        upperLeftCorner.y + size.height)
    ) ;
    
    // Pop layer before EndDraw
    g_pRenderTarget->PopLayer() ;
    
    g_pRenderTarget->EndDraw() ;

    效果图

    透明效果

    在PushLayer调用完之后,先绘制一个位图,然后再绘制三个矩形,这三个矩形使用绿颜色的画刷来绘制,所以最终的结果就是位图和矩形混合后的结果,可以看到矩形呈透明状,创建绿色画刷的代码省略。

    代码

    g_pRenderTarget->BeginDraw() ;
    
    g_pRenderTarget->PushLayer(D2D1::LayerParameters(), g_pLayer) ;
    
    g_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
    
    D2D1_SIZE_F size = g_pBitmap->GetSize() ;
    D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f) ;
    
    // Draw bitmap
    g_pRenderTarget->DrawBitmap(
        g_pBitmap,
        D2D1::RectF(
        upperLeftCorner.x,
        upperLeftCorner.y,
        upperLeftCorner.x + size.width,
        upperLeftCorner.y + size.height)
    ) ;
    
    // Opacity mask 1
    g_pRenderTarget->FillRectangle(D2D1::RectF(100, 100, 200, 200), g_pBlackBrush) ;
    
    // Opacity mask 2
    g_pRenderTarget->FillRectangle(D2D1::RectF(200, 200, 300, 300), g_pBlackBrush) ;
    
    // Opacity mask 3
    g_pRenderTarget->FillRectangle(D2D1::RectF(300, 300, 400, 400), g_pBlackBrush) ;
    
    // Pop layer before EndDraw
    g_pRenderTarget->PopLayer() ;
    
    g_pRenderTarget->EndDraw() ;

    效果图

    圆形渐变画刷

    先创建一个圆形的渐变色画刷,调用PushLayer的时候将这个画刷作为参数传递给PushLayer的第一个参数。接下来绘制一个位图,当调用PopLayer的时候两次绘制的内容将被混合到一起,最后形成一个夜视镜的效果。

    代码

    g_pRenderTarget->BeginDraw() ;
    
    // Clear background color to white
    g_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
    
    g_pRenderTarget->PushLayer(
        D2D1::LayerParameters(
            D2D1::InfiniteRect(),
            NULL,
            D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
            D2D1::IdentityMatrix(),
            1.0f,
            g_pRadialGradientBrush,
            D2D1_LAYER_OPTIONS_NONE),
            g_pLayer
    );
    
    D2D1_SIZE_F size = g_pBitmap->GetSize() ;
    D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f) ;
    
    // Draw bitmap
    g_pRenderTarget->DrawBitmap(
        g_pBitmap,
        D2D1::RectF(
        upperLeftCorner.x,
        upperLeftCorner.y,
        upperLeftCorner.x + size.width,
        upperLeftCorner.y + size.height)
    ) ;
    
    // Pop layer before EndDraw
    g_pRenderTarget->PopLayer() ;
    
    g_pRenderTarget->EndDraw() ;

    效果图

    最后一个例子代码下载

    == Happy Coding ==

    作者:zdd
    出处:http://www.cnblogs.com/graphics/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    How To Upgrade ASM from 10.2 to 11.1 (RAC)
    Moving ASM spfile to a shared device in RAC
    关于2019夏季小学期收获与感想
    大道至简读后感
    关于2017届学长制作分享软件share(失物招领)的使用体验和需改进的内容
    暑假周报告总结第三周
    暑假周报告总结第二周
    假期周进度报告第一周
    成功试验基于C#/.NET的Android开发
    基于Linux命令行终端的ftp客户端程序
  • 原文地址:https://www.cnblogs.com/graphics/p/2781969.html
Copyright © 2020-2023  润新知