Back-face culling

À esquerda, um modelo sem Back-face culling; à direita, o mesmo modelo com Back-face culling: as faces posteriores são removidas.

Na computação gráfica, Back-face culling determina quando um polígono presente em um objeto gráfico é visível. Essa é uma etapa do pipeline gráfico que testa se os pontos contidos em determinado polígono são exibidos no sentido horário ou anti-horário quando projetados na tela. Se o usuário previamente especificar que os polígonos estão voltados para a frente, um movimento no sentido horário acontece, mas se o polígono projetado na tela tem um movimento no sentido anti-horário, então ele foi girado para ficar de frente para a câmera e não será desenhado.

O processo implica renderizações mais rápidas e eficientes, reduzindo o número de polígonos necessários para o programa "desenhar" na tela. Em uma cena que contenha a rua de uma cidade, geralmente não há necessidade de desenhar os polígonos contidos nas laterais dos edifícios que estão de costas para a câmera.

Em geral, pode-se considerar que back-face culling não possui efeito visível em uma cena renderizada se ela contiver apenas geometria fechada e opaca. Em cenas contendo polígonos transparentes, os polígonos voltados para trás podem se tornar visíveis através do processo de composição alfa (alpha composition). Na renderização com wire-frame, back-face culling pode ser usado para resolver parcialmente o problema de remoção de linha oculta (hidden line removal), mas apenas para geometria convexa fechada.

Uma técnica relacionada é o clipping , que determina se os polígonos estão no campo de visão da câmera.

Outra técnica similar é a Z-culling, também conhecida como seleção de oclusão , que tenta pular o "desenho" de polígonos que estão fora do ponto de vista.

Implementação

Um método para implementação do back-face culling é descartar todos os triângulos onde o produto escalar de sua superfície normal e o vetor de câmera para triângulo for maior ou igual a zero.

( V 0 P ) N 0 {\displaystyle \left(V_{0}-P\right)\cdot N\geq 0} ( V 0 P ) N 0 {\displaystyle \left(V_{0}-P\right)\cdot N\geq 0}

onde P é o ponto de vista, V0 é o primeiro vértice de um triângulo e N é o seu normal, definido como um produto vetorial de dois vetores representando lados do triângulo adjacente a V0:

N = ( V 1 V 0 ) × ( V 2 V 0 ) {\displaystyle N=\left(V_{1}-V_{0}\right)\times \left(V_{2}-V_{0}\right)} N = ( V 1 V 0 ) × ( V 2 V 0 ) {\displaystyle N=\left(V_{1}-V_{0}\right)\times \left(V_{2}-V_{0}\right)}

Como o produto vetorial não é comutativo, definir o normal em termos de produto vetorial permite especificar a direção normal em relação à superfície do triângulo usando ''vertex order(winding)'' :

( V 1 V 0 ) × ( V 2 V 0 ) = ( V 2 V 0 ) × ( V 1 V 0 ) {\displaystyle \left(V_{1}-V_{0}\right)\times \left(V_{2}-V_{0}\right)=-\left(V_{2}-V_{0}\right)\times \left(V_{1}-V_{0}\right)}

Se os pontos já estiverem no espaço de visualização, P pode ser assumido como sendo (0, 0, 0) , a origem.

V 0 N 0 {\displaystyle -V_{0}\cdot N\geq 0}

Também é possível usar este método no espaço de projeção, representando a desigualdade acima como determinante de uma matriz e aplicando-lhe a matriz de projeção.[1]

Existe outro método baseado na paridade de reflexão, que é mais apropriada para duas dimensões onde a normal da superfície não pode ser calculada (também conhecida como verificação CCW).

Deixe um triângulo unitário em duas dimensões ( coordenadas homogêneas ) ser definido como

U 0 = [ 0 0 1 ] , U 1 = [ 1 0 1 ] , U 2 = [ 0 1 1 ] {\displaystyle U_{0}={\begin{bmatrix}0\\0\\1\end{bmatrix}},U_{1}={\begin{bmatrix}1\\0\\1\end{bmatrix}},U_{2}={\begin{bmatrix}0\\1\\1\end{bmatrix}}}

Então, para algum outro triângulo, também em duas dimensões,

V 0 = [ x 0 y 0 1 ] , V 1 = [ x 1 y 1 1 ] , V 2 = [ x 2 y 2 1 ] {\displaystyle V_{0}={\begin{bmatrix}x_{0}\\y_{0}\\1\end{bmatrix}},V_{1}={\begin{bmatrix}x_{1}\\y_{1}\\1\end{bmatrix}},V_{2}={\begin{bmatrix}x_{2}\\y_{2}\\1\end{bmatrix}}}

Definir uma matriz que transforma o triângulo da unidade nele

M = [ x 1 x 0 x 2 x 0 x 0 y 1 y 0 y 2 y 0 y 0 0 0 1 ] {\displaystyle M={\begin{bmatrix}x_{1}-x_{0}&x_{2}-x_{0}&x_{0}\\y_{1}-y_{0}&y_{2}-y_{0}&y_{0}\\0&0&1\end{bmatrix}}}

de modo a

M U 0 = V 0 {\displaystyle MU_{0}=V_{0}}
M U 1 = V 1 {\displaystyle MU_{1}=V_{1}}
M U 2 = V 2 {\displaystyle MU_{2}=V_{2}}

Descarte o triângulo se a matriz M contiver um número ímpar de reflexões (voltado para o lado oposto do triângulo unitário)

| M | < 0 {\displaystyle \left|M\right|<0}

O triângulo unitário é usado como uma referência e a transformação M é usada como um traço para dizer se a ordem do vértice é diferente entre dois triângulos. A única maneira pela qual a ordem dos vértices pode mudar em duas dimensões é por reflexão. A reflexão é um exemplo de função involutiva (com respeito à ordem do vértice), o número par de reflexões deixará o triângulo voltado para o mesmo lado, como se nenhuma reflexão fosse aplicada. Um número ímpar de reflexões deixará o triângulo voltado para o outro lado, como se exatamente depois de uma reflexão. Transformações contendo um número ímpar de reflexos sempre têm fator de escala negativo, assim como o fator de escala é positivo se não houver reflexos ou mesmo número deles. O fator de escala de uma transformação é calculado pelo determinante de sua matriz.

Referências

  1. David H. Eberly (2006). Projeto de motor de jogo 3D: uma abordagem prática para computação gráfica em tempo real , p. 69