一、实现思路
先绘制文字阴影部分,绘制阴影文本后应用3DTransform与高斯模糊特效,最后再正常绘制一次文本主体。
二、实现代码
hr = m_pDWriteFactory->CreateTextFormat(
sc_fontName,
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
sc_fontSize,
L"", //locale
&pTextFormat
);
pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
static const WCHAR sc_helloWorld[] = L"你好\nWorld!";
ID2D1SolidColorBrush *pGrayBrush = nullptr;
hr = m_pOffScreenRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::DarkGray),
&pGrayBrush);
hr = m_pDWriteFactory->CreateTextLayout(
sc_helloWorld,
ARRAYSIZE(sc_helloWorld) - 1,
pTextFormat,
m_width,
m_height,
&m_pTextLayout
);
m_pOffScreenRenderTarget->BeginDraw();
m_pOffScreenRenderTarget->Clear(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f));
m_pOffScreenRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
// 绘制文字阴影部分
m_pOffScreenRenderTarget->DrawTextLayout(D2D1::Point2F(0.0f, 0.0f), m_pTextLayout, pGrayBrush);
hr = m_pOffScreenRenderTarget->EndDraw();
// 创建特效并渲染到Bitmap
m_pOffScreenRenderTarget->QueryInterface(&m_pDeviceContext);
m_pOffScreenRenderTarget->CreateBitmapFromWicBitmap(m_pWicBitmap, &m_pBitmap);
// 高斯模糊
m_pDeviceContext->CreateEffect(CLSID_D2D1GaussianBlur, &m_pGaussianBlur);
m_pGaussianBlur->SetInput(0, m_pBitmap);
m_pGaussianBlur->SetValue(D2D1_GAUSSIANBLUR_PROP_BORDER_MODE, D2D1_BORDER_MODE_SOFT);
m_pGaussianBlur->SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, 1.0f);
// 镜像阴影
ID2D1Effect *pPerspectiveTransformEffect = nullptr;
m_pDeviceContext->CreateEffect(CLSID_D2D13DPerspectiveTransform, &pPerspectiveTransformEffect);
pPerspectiveTransformEffect->SetInputEffect(0, m_pGaussianBlur);
pPerspectiveTransformEffect->SetValue(D2D1_3DPERSPECTIVETRANSFORM_PROP_ROTATION_ORIGIN,
D2D1::Vector3F(m_width / 2.0f, m_height / 2.0f, 0.0f));
pPerspectiveTransformEffect->SetValue(D2D1_3DPERSPECTIVETRANSFORM_PROP_ROTATION,
D2D1::Vector3F(180.0f, 0.0f, 0.0f));
pPerspectiveTransformEffect->SetValue(D2D1_3DPERSPECTIVETRANSFORM_PROP_GLOBAL_OFFSET,
D2D1::Vector3F(0.0f, sc_fontSize * GetTextLines(sc_helloWorld), 0.0f));
m_pDeviceContext->BeginDraw();
m_pDeviceContext->Clear(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f));
m_pDeviceContext->SetTransform(D2D1::Matrix3x2F::Identity());
m_pDeviceContext->DrawImage(pPerspectiveTransformEffect, D2D1_INTERPOLATION_MODE_LINEAR);
hr = m_pDeviceContext->EndDraw();
// 绘制文字本体部分
if (SUCCEEDED(hr))
{
m_pOffScreenRenderTarget->BeginDraw();
ID2D1SolidColorBrush *pBlackBrush = nullptr;
hr = m_pOffScreenRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&pBlackBrush);
m_pOffScreenRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
m_pOffScreenRenderTarget->DrawTextLayout(D2D1::Point2F(0.0f, 0.0f), m_pTextLayout, pBlackBrush);
hr = m_pOffScreenRenderTarget->EndDraw();
}
四、总结
1、整个实现过程包含了三次绘制,第一次绘制的文本是为后面应用特效做准备的,第二次绘制应用了高斯模糊和3D变换,将第一次绘制的文本变换为镜像阴影的效果,最后一次是正常绘制文本主体。
2、在对原文本进行3D变换的时候,这里先对文字绕X轴旋转180度,然后向下偏移n * fontSize,n为文本中包含的行数。
3、上面的实现方法只能将文本整体进行镜像处理,没法实现每一行文字单独镜像。如果要实现每行单独镜像,自己的思路是单独绘制每一行的文本,然后应用上面的方法绘制对应的阴影,重复上述过程,直到绘制完所有的文字。
PS:
本文代码是基于微软官方文档示例实现的,详情可参考这里。