Visão geral de realizações de geometria
Este tópico descreve como usar Direct2D realizações de geometria para melhorar o desempenho de renderização de geometria do aplicativo em determinados cenários.
Ele contém as seções a seguir:
- O que são realizações de geometria?
- Por que usar realizações de geometria?
- Quando usar as realizações de geometria
- Criando realizações de geometria
- Realizações de geometria de desenho
- Dimensionamento de realizações de geometria
- Tópicos relacionados
O que são realizações de geometria?
As realizações de geometria, introduzidas em Windows 8.1, são um novo tipo de primitivo de desenho que facilita a Direct2D aplicativos melhorarem o desempenho de renderização de geometria em determinados casos. As realizações de geometria são representadas pela interface ID2D1GeometryRealization .
Por que usar realizações de geometria?
Quando Direct2D renderiza um objeto ID2D1Geometry, ele deve converter essa geometria em uma forma que o hardware gráfico entenda por meio de um processo chamado mosaico. Normalmente, Direct2D deve ter geometria de mosaico a cada quadro desenhado, mesmo que a geometria não mude. Se o aplicativo renderizar a mesma geometria a cada quadro, a repetição de mosaico representará o esforço computacional desperdiçado. É mais eficiente computacionalmente armazenar em cache o mosaico ou até mesmo a rasterização completa da geometria e desenhar essa representação armazenada em cache em cada quadro em vez de reassolar repetidamente.
Uma maneira comum de os desenvolvedores resolverem esse problema é armazenar em cache a rasterização completa da geometria. Em particular, é comum criar um novo bitmap, rasterizar a geometria para esse bitmap e, em seguida, desenhar esse bitmap para a cena conforme necessário. (Essa abordagem é descrita na seção Renderização geometry de Melhorando o desempenho de aplicativos de Direct2D.) Embora essa abordagem seja muito eficiente computacionalmente, ela tem algumas desvantagens:
- O bitmap armazenado em cache é sensível a alterações na transformação aplicada à cena. Por exemplo, dimensionar a rasterização pode resultar em artefatos de dimensionamento perceptíveis. Atenuar esses artefatos com algoritmos de dimensionamento de alta qualidade pode ser computacionalmente caro.
- O bitmap armazenado em cache consome uma quantidade significativa de memória, especialmente se for rasterizado em alta resolução.
As realizações de geometria fornecem uma maneira alternativa de armazenar geometria em cache que evita as desvantagens acima. As realizações de geometria não são representadas por pixels (como é o caso com uma rasterização completa), mas por pontos em um plano matemático. Por esse motivo, eles são menos sensíveis do que as rasterizações completas para dimensionamento e outras manipulações, e consomem significativamente menos memória.
Quando usar as realizações de geometria
Considere o uso de realizações de geometria quando seu aplicativo renderiza geometrias complexas cujas formas mudam com pouca frequência, mas que podem estar sujeitas a transformações em alteração.
Por exemplo, considere um aplicativo de mapeamento que mostra um mapa estático, mas que permite que o usuário amplie e reduza. Esse aplicativo pode se beneficiar do uso de realizações de geometria. Como as geometrias que estão sendo renderizadas permanecem estáticas, é útil armazená-las em cache para salvar o trabalho de mosaico. Mas como os mapas são dimensionados quando o usuário amplia, armazenar em cache uma rasterização completa não é o ideal, devido ao dimensionamento de artefatos. As realizações de geometria de cache permitiriam que o aplicativo evitasse o trabalho de mosaico novamente, mantendo a alta qualidade visual durante o dimensionamento.
Por outro lado, considere um aplicativo de caleidoscópio com geometria animada que muda continuamente. Esse aplicativo provavelmente não se beneficiaria do uso de realizações de geometria. Como as próprias formas mudam de quadro para quadro, não é útil armazenar em cache suas mosaicos. A melhor abordagem para este aplicativo é desenhar objetos ID2D1Geometry diretamente.
Criando realizações de geometria
Um objeto ID2D1GeometryRealization deve ser criado a partir de um objeto ID2D1Geometry existente. Para criar uma realização de geometria, chame o método CreateFilledGeometryRealization ou o método CreateStrokedGeometryRealization e passe a ID2D1Geometry para ser realizado.
- CreateFilledGeometryRealization cria uma realização do interior da forma: a região que seria desenhada chamando FillGeometry.
- CreateStrokedGeometryRealization cria uma realização do traço da forma: a região que seria desenhada chamando DrawGeometry.
Ambos os tipos de realização de geometria são representados pela interface ID2D1GeometryRealization .
Ao criar uma realização de geometria, Direct2D deve nivelar as curvas na geometria fornecida para aproximações poligonais. Você deve fornecer um parâmetro de tolerância de nivelamento para o método de criação , que especifica a distância máxima, em DIPs (pixels independentes de dispositivo), entre a curva verdadeira da geometria e sua aproximação poligonal. Quanto menor a tolerância de nivelamento fornecida, maior será a fidelidade do objeto de realização de geometria resultante. Da mesma forma, fornecer uma tolerância de nivelamento mais alta produz uma realização de geometria de menor fidelidade. Observe que as realizações de geometria de maior fidelidade são mais caras de desenhar do que as de menor fidelidade, mas podem ser dimensionadas ainda mais antes de introduzir artefatos visíveis. Para obter diretrizes sobre como usar tolerâncias de nivelamento, consulte Dimensionando as realizações de geometria abaixo.
Observação
Os objetos de realização de geometria estão associados a um dispositivo gráfico específico: eles são recursos dependentes do dispositivo.
Realizações de geometria de desenho
As realizações de geometria de desenho são semelhantes ao desenho de outros primitivos Direct2D, como bitmaps. Para fazer isso, chame o método DrawGeometryRealization e passe o objeto de realização de geometria a ser desenhado e o pincel a ser usado. Assim como acontece com outros métodos de desenho Direct2D, você deve chamar DrawGeometryRealization entre chamadas para BeginDraw e EndDraw.
Dimensionamento de realizações de geometria
As realizações de geometria, como outras Direct2D primitivas, respeitam o conjunto de transformações no contexto do dispositivo. Embora as transformações de tradução e rotação não tenham efeito sobre a qualidade visual das realizações de geometria, as transformações de escala podem produzir artefatos visuais.
Em particular, aplicar uma escala grande o suficiente a qualquer realização de geometria pode revelar a aproximação poligonal das curvas verdadeiras. A imagem aqui mostra um par de realizações de geometria elíptica (preenchimento e traço) que foram dimensionadas muito longe. Artefatos de nivelamento de curva são visíveis.
Aplicativos sensíveis à qualidade visual devem tomar medidas para garantir que isso não aconteça. A forma como você lida com o dimensionamento depende das necessidades do seu aplicativo. A seguir estão várias abordagens recomendadas para vários tipos diferentes de aplicativo.
Usando realizações de geometria em aplicativos que não são dimensionados
Se o aplicativo não executar nenhum dimensionamento nas realizações de geometria, será seguro criar as realizações apenas uma vez, usando uma única tolerância de nivelamento. (Transformações não dimensionadas não afetam a qualidade visual das realizações de geometria renderizadas.) Use a função ComputeFlatteningTolerance para calcular a tolerância de nivelamento apropriada para o DPI:
float dpiX, dpiY;
deviceContext->GetDpi(&dpiX, &dpiY);
float flatteningTolerance = D2D1::ComputeFlatteningTolerance(
D2D1::Matrix3x2F::Identity(), // apply no additional scaling transform
dpiX, // horizontal DPI
dpiY // vertical DPI
);
Usando realizações de geometria em aplicativos que são dimensionados em uma pequena quantidade
Se o aplicativo puder dimensionar uma realização de geometria em apenas uma pequena quantidade (por exemplo, até 2x ou 3x), talvez seja apropriado simplesmente criar a realização de geometria uma vez, em uma tolerância de nivelamento proporcionalmente menor do que o padrão. Isso cria uma realização de maior fidelidade que pode ser ampliada significativamente antes de incorrer em artefatos de dimensionamento; a compensação é que desenhar a realização de maior fidelidade requer mais trabalho.
Por exemplo, suponha que você saiba que seu aplicativo nunca dimensionará uma realização de geometria em mais de 2x. Seu aplicativo pode criar a realização de geometria usando uma tolerância de nivelamento que é metade do valor padrão e simplesmente dimensionar a realização conforme necessário, até 2x. Use a função ComputeFlatteningTolerance para calcular a tolerância de nivelamento apropriada passando 2.0 como o parâmetro maxZoomFactor :
float dpiX, dpiY;
deviceContext->GetDpi(&dpiX, &dpiY);
float flatteningTolerance = D2D1::ComputeFlatteningTolerance(
D2D1::Matrix3x2F::Identity(), // apply no additional scaling transform
dpiX, // horizontal DPI
dpiY, // vertical DPI
2.0f // realization can be scaled by an additional 2x
);
Usando realizações de geometria em aplicativos que são dimensionados em uma grande quantidade
Se seu aplicativo puder dimensionar uma realização de geometria para cima ou para baixo em grandes quantidades (por exemplo, em 10x ou mais), lidar com o dimensionamento adequadamente é mais complicado.
Para a maioria desses aplicativos, a abordagem recomendada é recriar a realização de geometria em tolerâncias de nivelamento progressivamente menores à medida que a cena é escalada verticalmente, a fim de manter a fidelidade visual e evitar o dimensionamento de artefatos. Da mesma forma, à medida que a cena é dimensionada para baixo, o aplicativo deve recriar as realizações de geometria em tolerâncias de nivelamento progressivamente mais altas, a fim de evitar a renderização desperdiçada de detalhes que não são visíveis. O aplicativo não deve recriar as realizações de geometria toda vez que a escala muda, pois isso derrota a finalidade de armazenar em cache o trabalho de mosaico. Em vez disso, o aplicativo deve recriar as realizações de geometria com menos frequência: por exemplo, após cada aumento de 2x ou diminuição na escala.
Sempre que a escala muda em um aplicativo em resposta à interação do usuário, o aplicativo pode comparar a nova escala com a escala na qual as realizações de geometria foram criadas pela última vez (armazenadas, por exemplo, em um membro m_lastScale ). Se os dois valores estiverem próximos (nesse caso, dentro de um fator de 2), nenhuma ação adicional será tomada. Mas se os dois valores não estiverem próximos, as realizações de geometria serão recriadas. A função ComputeFlatteningTolerance é usada para calcular uma tolerância de nivelamento apropriada para a nova escala e m_lastScale é atualizada para a nova escala.
Além disso, o aplicativo sempre cria realizações usando uma tolerância menor do que o que normalmente seria usado para a nova escala, passando um valor de 2 como o parâmetro maxZoomFactor para ComputeFlatteningTolerance. Isso permite que as novas realizações de geometria sejam escaladas verticalmente por um fator adicional de 2 sem incorrer em artefatos de dimensionamento.
Observação
A abordagem descrita aqui pode não ser apropriada para todos os aplicativos. Por exemplo, se o aplicativo permitir que a cena seja dimensionada por fatores muito grandes muito rapidamente (por exemplo, se ele contiver um controle deslizante "zoom" que pode ser movido de 100% para 1.000.000% no intervalo de alguns quadros), essa abordagem pode resultar em excesso de trabalho recriando as realizações de geometria a cada quadro. Uma abordagem alternativa é recriar as realizações de geometria somente após a conclusão de cada manipulação da escala da cena (por exemplo, depois que o usuário concluir um gesto de pinçagem).
Tópicos relacionados
Melhorando o desempenho de aplicativos Direct2D
Diretrizes gerais para renderizar conteúdo estático complexo