Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Esta visão geral descreve os conceitos básicos do uso de camadas Direct2D. Contém as seguintes secções.
- O que são camadas?
- Camadas no Windows 8 e versões posteriores
- Criação de camadas
- Limites de conteúdo
- Máscaras Geométricas
- Máscaras de opacidade
- Alternativas às camadas
- Cortar uma forma arbitrária
- Tópicos relacionados
O que são camadas?
As camadas, representadas por objetos ID2D1Layer , permitem que um aplicativo manipule um grupo de operações de desenho. Você usa uma camada "empurrando-a" para um destino de renderização. As operações subsequentes de desenho do alvo de renderização são direcionadas para a camada. Depois de terminar com a camada, retira-se a camada do alvo de renderização, que compõe o conteúdo da camada de volta para o alvo de renderização.
Como os pincéis, as camadas são recursos dependentes do dispositivo criados por destinos de renderização. As camadas podem ser usadas em qualquer destino de renderização no mesmo domínio de recurso que contém o destino de renderização que o criou. No entanto, um recurso de camada só pode ser usado por um destino de renderização de cada vez. Para obter mais informações sobre recursos, consulte Visão geral de recursos.
Embora as camadas ofereçam uma poderosa técnica de renderização para produzir efeitos interessantes, o número excessivo de camadas em um aplicativo pode afetar negativamente seu desempenho, devido aos vários custos associados ao gerenciamento de camadas e recursos de camadas. Por exemplo, há o custo de encher ou limpar a camada e depois misturá-la de volta, especialmente em hardware mais avançado. Em seguida, há o custo de gerenciar os recursos da camada. Se os realocar frequentemente, os atrasos resultantes na GPU serão o problema mais significativo. Ao projetar seu aplicativo, tente maximizar a reutilização de recursos de camada.
Camadas no Windows 8 e versões posteriores
O Windows 8 introduziu novas APIs relacionadas à camada que simplificam, melhoram o desempenho e adicionam recursos às camadas.
ID2D1DeviceContext e PushLayer
A interface ID2D1DeviceContext é derivada da interface ID2D1RenderTarget e é fundamental para exibir conteúdo Direct2D no Windows 8, para mais informações sobre esta interface, consulte Devices and Device Contexts. Com a interface de contexto do dispositivo, pode ignorar a chamada do método CreateLayer e, em seguida, passar NULL para o método ID2D1DeviceContext::PushLayer. O Direct2D gerencia automaticamente o recurso de camada e pode compartilhar recursos entre camadas e gráficos de efeitos.
D2D1_LAYER_PARAMETERS1 e D2D1_LAYER_OPTIONS1
A estrutura D2D1_LAYER_PARAMETERS1 é a mesma que D2D1_LAYER_PARAMETERS, exceto que o membro final da estrutura é agora uma enumeração D2D1_LAYER_OPTIONS1 .
D2D1_LAYER_OPTIONS1 não tem nenhuma opção ClearType e tem duas opções diferentes que você pode usar para melhorar o desempenho:
D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND: O Direct2D renderiza primitivas na camada sem a limpar, reutilizando um fundo preto transparente. Este não é o padrão, mas na maioria dos casos resulta em melhor desempenho.
D2D1_LAYER_OPTIONS1_IGNORE_ALPHA: se a superfície subjacente estiver definida como D2D1_ALPHA_MODE_IGNORE, esta opção permite que o Direct2D evite modificar o canal alfa da camada. Não utilize isto noutros casos.
Modos de mistura
A partir do Windows 8, o contexto do dispositivo tem um modo de mesclagem primitivo que determina como cada primitiva é misturada com a superfície de destino. Esse modo também se aplica a camadas quando você chama o método PushLayer .
Por exemplo, se você estiver usando uma camada para recortar primitivas com transparência, defina o modo D2D1_PRIMITIVE_BLEND_COPY no contexto do dispositivo para obter resultados adequados. O modo de cópia faz com que o contexto do dispositivo interpole linearmente todos os 4 canais de cor, incluindo o canal alfa, de cada pixel com o conteúdo da superfície alvo de acordo com a máscara geométrica da camada.
Interoperação
A partir do Windows 8, o Direct2D suporta a interoperação com Direct3D e GDI quando uma camada ou clipe é ativado. Você chama ID2D1GdiInteropRenderTarget::GetDC enquanto uma camada é enviada por push para interoperar com o GDI. Você chama ID2D1DeviceContext::Flush e em seguida renderiza para a superfície subjacente para interoperar com o Direct3D. É sua responsabilidade renderizar dentro da camada ou clipe com Direct3D ou GDI. Se você tentar renderizar fora da camada ou clipe, os resultados serão indefinidos.
Criação de camadas
Trabalhar com camadas requer familiaridade com os métodos CreateLayer, PushLayer e PopLayer , e com a estrutura D2D1_LAYER_PARAMETERS , que contém um conjunto de dados paramétricos que define como a camada pode ser usada. A lista a seguir descreve os métodos e a estrutura.
Chame o método CreateLayer para criar um recurso de camada.
Observação
A partir do Windows 8, você pode ignorar a chamada do método CreateLayer e, em seguida, passar NULL para o método PushLayer na interface ID2D1DeviceContext . Isso é mais simples e permite que o Direct2D gerencie automaticamente o recurso de camada e compartilhe recursos entre camadas e gráficos de efeitos.
Depois que o destino de renderização começar a desenhar (depois que seu método BeginDraw tiver sido chamado), você poderá usar o método PushLayer . O método PushLayer adiciona a camada especificada ao destino de renderização, para que o destino receba todas as operações de desenho subsequentes até que PopLayer seja chamado. Esse método usa um objeto ID2D1Layer retornado chamando CreateLayer e um layerParameters na estrutura D2D1_LAYER_PARAMETERS . A tabela a seguir descreve os campos da estrutura.
Campo Descrição limitesDeConteúdo Os limites de conteúdo da camada. O conteúdo não será renderizado fora desses limites. O padrão desse parâmetro é InfiniteRect. Quando o valor padrão é usado, os limites de conteúdo são efetivamente considerados como os limites do destino de renderização. geometricMask (Opcional) A área, definida por uma ID2D1Geometry, para a qual a camada deve ser cortada. Defina como NULL se a camada não deve ser recortada por uma geometria. máscaraAntialiasMode Um valor que especifica o modo de anti-aliasing para a máscara geométrica, conforme indicado pelo campo geometricMask. maskTransform Um valor que especifica a transformação que é aplicada à máscara geométrica ao compor a camada. Isso é relativo à transformação do mundo. opacidade O valor de opacidade da camada. A opacidade de cada recurso na camada é multiplicada por este valor ao montar no alvo. opacidadePincel (Opcional) Um pincel que é usado para modificar a opacidade da camada. O pincel é mapeado para a camada e o canal alfa de cada pixel de pincel mapeado é multiplicado em relação ao pixel da camada correspondente. Defina como NULL se a camada não tiver uma máscara de opacidade. layerOptions Um valor que especifica se a camada pretende renderizar texto com antialiasing ClearType, uma tecnologia de suavização de texto. O parâmetro, por padrão, está desativado. Ativá-lo permite que o ClearType funcione corretamente, mas resulta em uma velocidade de renderização um pouco mais lenta. Observação
A partir do Windows 8, você não pode renderizar com ClearType em uma camada, portanto, o parâmetro layerOptions sempre deve ser definido como D2D1_LAYER_OPTIONS_NONE
Por conveniência, o Direct2D fornece o método D2D1::LayerParameters para ajudá-lo a criar estruturas D2D1_LAYER_PARAMETERS .
Para compor o conteúdo da camada no destino de renderização, chame o método PopLayer . Você deve chamar o método PopLayer antes de chamar o método EndDraw .
O exemplo a seguir mostra como usar CreateLayer, PushLayer e PopLayer. Todos os campos na estrutura D2D1_LAYER_PARAMETERS são definidos como padrão, exceto opacityBrush, que é definido como ID2D1RadialGradientBrush.
// 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);
O código foi omitido deste exemplo.
Observe que quando você chamar PushLayer e PopLayer, certifique-se de que cada PushLayer tenha uma chamada PopLayer correspondente. Se houver mais chamadas PopLayer do que chamadas PushLayer , o destino de renderização será colocado em um estado de erro. Se Flush for chamado antes de todas as camadas pendentes serem exibidas, o destino de renderização será colocado em um estado de erro e retornará um erro. Para limpar o estado de erro, use EndDraw.
Limites de conteúdo
O contentBounds define o limite do que deve ser desenhado para a camada. Somente os elementos dentro dos limites do conteúdo são combinados novamente para o alvo de renderização.
O exemplo a seguir mostra como especificar contentBounds para que a imagem original seja recortada para as bordas de conteúdo com o canto superior esquerdo em (10, 108) e o canto inferior direito em (121, 177). A ilustração seguinte mostra a imagem original e o resultado de recortar a imagem conforme os limites de conteúdo.
HRESULT DemoApp::RenderWithLayerWithContentBounds(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, 0));
// Push the layer with the content bounds.
pRT->PushLayer(
D2D1::LayerParameters(D2D1::RectF(10, 108, 121, 177)),
pLayer
);
pRT->DrawBitmap(m_pWaterBitmap, D2D1::RectF(0, 0, 128, 192));
pRT->PopLayer();
}
SafeRelease(&pLayer);
return hr;
}
O código foi omitido deste exemplo.
Observação
A imagem cortada resultante será ainda mais afetada se você especificar um geometricMask. Consulte a seção Máscaras geométricas para obter mais informações.
Máscaras Geométricas
Uma máscara geométrica é um clipe ou um recorte, definido por um objeto ID2D1Geometry , que mascara uma camada quando ela é desenhada por um destino de renderização. Você pode usar o campo geometricMask da estrutura D2D1_LAYER_PARAMETERS para mascarar os resultados para uma geometria. Por exemplo, se você quiser exibir uma imagem mascarada por uma letra de bloco "A", você pode primeiro criar uma geometria representando a letra de bloco "A" e usar essa geometria como uma máscara geométrica para uma camada. Então, depois de empurrar a camada, você pode desenhar a imagem. Estourar a camada resulta na imagem sendo cortada para a forma de letra de bloco "A".
O exemplo a seguir mostra como criar um ID2D1PathGeometry contendo uma forma de uma montanha e, em seguida, passar a geometria do caminho para o PushLayer. Em seguida, desenha um bitmap e quadrados. Se houver apenas um bitmap na camada para renderizar, use FillGeometry com um pincel de bitmap fixo para eficiência. A ilustração a seguir mostra a saída do exemplo.
O primeiro exemplo define a geometria a ser usada como máscara.
hr = m_pD2DFactory->CreatePathGeometry(&m_pPathGeometry);
if(SUCCEEDED(hr))
{
ID2D1GeometrySink *pSink = NULL;
// Write to the path geometry using the geometry sink.
hr = m_pPathGeometry->Open(&pSink);
if (SUCCEEDED(hr))
{
pSink->SetFillMode(D2D1_FILL_MODE_WINDING);
pSink->BeginFigure(
D2D1::Point2F(0, 90),
D2D1_FIGURE_BEGIN_FILLED
);
D2D1_POINT_2F points[7] = {
D2D1::Point2F(35, 30),
D2D1::Point2F(50, 50),
D2D1::Point2F(70, 45),
D2D1::Point2F(105, 90),
D2D1::Point2F(130, 90),
D2D1::Point2F(150, 60),
D2D1::Point2F(170, 90)
};
pSink->AddLines(points, 7);
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
hr = pSink->Close();
}
SafeRelease(&pSink);
}
O próximo exemplo usa a geometria como uma máscara para a camada.
HRESULT DemoApp::RenderWithLayerWithGeometricMask(ID2D1RenderTarget *pRT)
{
HRESULT hr;
// Create a layer.
ID2D1Layer *pLayer = NULL;
hr = pRT->CreateLayer(NULL, &pLayer);
if (SUCCEEDED(hr))
{
pRT->SetTransform(D2D1::Matrix3x2F::Translation(300, 450));
pRT->PushLayer(
D2D1::LayerParameters(D2D1::InfiniteRect(), m_pPathGeometry),
pLayer
);
pRT->DrawBitmap(m_pLeafBitmap, D2D1::RectF(0, 0, 198, 132));
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;
}
O código foi omitido deste exemplo.
Observação
Em geral, se você especificar um geometricMask, poderá usar o valor padrão, InfiniteRect, para contentBounds.
Se contentBounds é NULL e geometricMask não é NULL, os limites de conteúdo serão efetivamente os limites da máscara geométrica após aplicada a transformação da máscara.
Se contentBounds é não-NULL e geometricMask é não-NULL, então a máscara geométrica transformada será efetivamente cortada em relação aos limites de conteúdo, assumindo-se que os limites de conteúdo são infinitos.
Máscaras de opacidade
Uma máscara de opacidade é uma máscara, descrita por um pincel ou bitmap, que é aplicada a outro objeto para tornar esse objeto parcial ou completamente transparente. Ele permite o uso do canal alfa de um pincel para ser usado como uma máscara de conteúdo. Por exemplo, você pode definir um pincel de gradiente radial que varia de opaco a transparente para criar um efeito de vinheta.
O exemplo a seguir usa um ID2D1RadialGradientBrush (m_pRadialGradientBrush) como uma máscara de opacidade. Em seguida, desenha um bitmap e quadrados. Se houver apenas um bitmap na camada para renderizar, use FillGeometry com um pincel de bitmap fixo para eficiência. A ilustração a seguir mostra a saída deste exemplo.
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;
}
O código foi omitido deste exemplo.
Observação
Este exemplo usa uma camada para aplicar uma máscara de opacidade a um único objeto para manter o exemplo o mais simples possível. Ao aplicar uma máscara de opacidade a um único objeto, é mais eficiente usar os métodos FillOpacityMask ou FillGeometry em vez de uma camada.
Para obter instruções sobre como aplicar uma máscara de opacidade sem usar uma camada, consulte a Visão geral das máscaras de opacidade.
Alternativas às camadas
Como mencionado anteriormente, o número excessivo de camadas pode afetar negativamente o desempenho do seu aplicativo. Para melhorar o desempenho, evite usar camadas sempre que possível; em vez disso, use suas alternativas. O exemplo de código a seguir mostra como usar PushAxisAlignedClip e PopAxisAlignedClip para recortar uma região, como uma alternativa ao uso de uma camada com limites de conteúdo.
pRT->PushAxisAlignedClip(
D2D1::RectF(20, 20, 100, 100),
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE
);
pRT->FillRectangle(D2D1::RectF(0, 0, 200, 133), m_pOriginalBitmapBrush);
pRT->PopAxisAlignedClip();
Da mesma forma, use FillGeometry com um pincel de bitmap fixo como uma alternativa ao uso de uma camada com uma máscara de opacidade quando houver apenas um conteúdo na camada para renderizar, conforme mostrado no exemplo a seguir.
m_pRenderTarget->FillGeometry(
m_pRectGeo,
m_pLinearFadeFlowersBitmapBrush,
m_pLinearGradientBrush
);
Como alternativa ao uso de uma camada com uma máscara geométrica, considere o uso de uma máscara de bitmap para recortar uma região, conforme mostrado no exemplo a seguir.
// 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_pOriginalBitmapBrush,
D2D1_OPACITY_MASK_CONTENT_GRAPHICS,
&rcBrushRect,
NULL
);
m_pRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
Por fim, se você quiser aplicar opacidade a um único primitivo, você deve multiplicar a opacidade na cor do pincel e, em seguida, renderizar o primitivo. Você não precisa de uma camada ou um bitmap de máscara de opacidade.
float opacity = 0.9f;
ID2D1SolidColorBrush *pBrush = NULL;
hr = pCompatibleRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(0.93f, 0.94f, 0.96f, 1.0f * opacity)),
&pBrush
);
m_pRenderTarget->FillRectangle(
D2D1::RectF(50.0f, 50.0f, 75.0f, 75.0f),
pBrush
);
Recortar uma forma arbitrária
A figura aqui mostra o resultado da aplicação de um clipe a uma imagem.
Você pode obter esse resultado usando camadas com uma máscara de geometria ou o método FillGeometry com um pincel de opacidade.
Aqui está um exemplo que usa uma camada:
// Call PushLayer() and pass in the clipping geometry.
m_d2dContext->PushLayer(
D2D1::LayerParameters(
boundsRect,
geometricMask));
Aqui está um exemplo que usa o método FillGeometry:
// Create an opacity bitmap and render content.
m_d2dContext->CreateBitmap(size, nullptr, 0,
D2D1::BitmapProperties(
D2D1_BITMAP_OPTIONS_TARGET,
D2D1::PixelFormat(
DXGI_FORMAT_A8_UNORM,
D2D1_ALPHA_MODE_PREMULTIPLIED),
dpiX, dpiY),
&opacityBitmap);
m_d2dContext->SetTarget(opacityBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();
// Create an opacity brush from the opacity bitmap.
m_d2dContext->CreateBitmapBrush(opacityBitmap.Get(),
D2D1::BitmapBrushProperties(),
D2D1::BrushProperties(),
&bitmapBrush);
// Call the FillGeometry method and pass in the clip geometry and the opacity brush
m_d2dContext->FillGeometry(
clipGeometry.Get(),
brush.Get(),
opacityBrush.Get());
Neste exemplo de código, quando você chama o método PushLayer, você não passa em uma camada criada pelo aplicativo. O Direct2D cria uma camada para você. O Direct2D é capaz de gerenciar a alocação e a destruição desse recurso sem qualquer envolvimento do aplicativo. Isso permite que o Direct2D reutilize camadas internamente e aplique otimizações de gerenciamento de recursos.
Observação
No Windows 8, muitas otimizações foram feitas para o uso de camadas e recomendamos que você tente usar APIs de camada em vez de FillGeometry sempre que possível.
Clipes alinhados ao eixo
Se a região a ser cortada estiver alinhada ao eixo da superfície de desenho, em vez de arbitrária. Este estojo é adequado para usar um retângulo de clipe em vez de uma camada. O ganho de desempenho é maior para geometria com aliasing do que para geometria com antialiasing. Para saber mais sobre clipes alinhados por eixo, veja o tópico PushAxisAlignedClip.
Tópicos relacionados