如何将效果应用于基元

本主题演示如何将一系列效果应用于 Direct2DDirectWrite 基元。

可以使用 Direct2D 效果 API 将效果图应用于 由 Direct2D 呈现到图像的基元。 此处的示例包含两个圆角矩形和文本“Direct2D”。 使用 Direct2D 绘制矩形,使用DirectWrite绘制文本。

包含文本“direct2d”的矩形。

使用 Direct2D 效果,可以使此图像看起来像下一个图像。 将 高斯模糊点反射照明算术合成复合 效果应用于 2D 基元,以在此处创建图像。

应用多个效果后,文本为“direct2d”的矩形。

将矩形和文本呈现到中间图面后,可以将它用作图像图中 ID2D1Effect 对象的输入。

在此示例中,将原始图像设置为 高斯模糊效果 的输入,然后将模糊的输出设置为 点反射照明效果的输入。 然后,此效果的结果与原始图像组合两次,以获取呈现到窗口的最终图像。

下面是图像图的示意图。

效果图示意图。

此效果图由四个 ID2D1Effect 对象组成,每个对象表示不同的内置效果。 可以使用 ID1D1Factory1::RegisterEffect 注册自定义效果后,以相同的方式创建和连接它们。 此处的代码创建效果、设置属性并连接前面所示的效果图。

  1. 使用 ID2D1DeviceContext::CreateEffect 方法并指定正确的 CLSID 创建高斯模糊效果。 内置效果的 CLSID 在 d2d1effects.h 中定义。 然后,使用 ID2D1Effect::SetValue 方法设置模糊的标准偏差。

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

    高斯模糊效果模糊图像的所有通道,包括 alpha 通道。

  2. 创建 反射照明 效果并设置属性。 光的位置是 3 个浮点值的矢量,因此必须将其声明为单独的变量,并将其传递给 SetValue 方法。

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

    反射照明效果使用输入的 alpha 通道为照明创建高度贴图。

  3. 可以使用 复合 效果和 算术复合效果两种不同的复合效果。 此效果图同时使用两者。

    创建 复合 效果并将模式设置为 D2D1_COMPOSITE_MODE_SOURCE_IN,这将输出源图像和目标图像的交集。

    算术复合效果基于万维网联合会 (W3C) 为可缩放矢量图形 (SVG) 标准定义的公式组成两个输入图像。 创建算术复合并设置公式的系数。

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

    此处显示了 算术复合 效果的系数。

    D2D1_VECTOR_4F sc_arithmeticCoefficients   = D2D1::Vector4F(0.0f, 1.0f, 1.0f, 0.0f);
    

    在此效果图中,这两个复合效果都采用其他效果和中间表面的输出作为输入并组合它们。

  4. 最后,通过将输入设置为正确的图像和位图来连接效果以形成图形。

    第一种效果 高斯模糊从将基元呈现到的中间图面接收其输入。 使用 ID2D1Effect::SetInput 方法并指定 ID2D1Image 对象的索引来设置输入。 高斯模糊和 反射照明 效果只有一个输入。 反射照明效果使用高斯模糊的模糊 alpha 通道

    复合算术复合效果具有多个输入。 若要确保图像按正确的顺序放在一起,必须为每个输入图像指定正确的索引。

    // 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());
    
  5. 算术复合 效果对象传递到 ID2DDeviceContext::D rawImage 方法中,它处理和绘制图形的输出。

        // Draw the output of the effects graph.
        m_d2dContext->DrawImage(
            m_arithmeticCompositeEffect.Get(),
            D2D1::Point2F(
                (size.width - sc_inputBitmapSize.width) / 2,
                (size.height - sc_inputBitmapSize.height) / 2 + sc_offset
                )
            );