Eu vejo algumas abordagens amplas por aí para fazer cel shading:
- Duplicação e ampliação do modelo com normais invertidas (não é uma opção para mim)
- Abordagens de filtro / sombreador Sobel para detecção de borda
- Abordagens de buffer de estêncil para detecção de bordas
- Abordagens de sombreamento de geometria (ou vértice) que calculam normais de face e aresta
Estou correto ao supor que a abordagem centrada na geometria oferece a maior quantidade de controle sobre a iluminação e a espessura da linha, bem como por exemplo. para terrenos onde você pode ver a linha de silhueta de uma colina se fundindo gradualmente em uma planície?
E se eu não precisasse de iluminação com pixels nas superfícies do meu terreno? (E provavelmente não o planejarei usar iluminação / sombreamento com base em vértices ou em mapas de textura com base em células.) Seria melhor seguir a abordagem do tipo geometria ou optar por uma abordagem de espaço / fragmento de tela? para manter as coisas mais simples? Se sim, como obteria a "tinta" das colinas na silhueta da malha, em vez de apenas o contorno de toda a malha (sem detalhes de "tinta" dentro desse contorno? (AKA , contornos sugestivos , vincos )).
Por fim, é possível emular de maneira barata a abordagem de inversão de normais, usando um sombreador de geometria? Minha preocupação com isso é que eu certamente poderia duplicar todos os vértices e escaloná-los de acordo, mas como eu abordaria os normais invertidos e as cores distintas no shader de fragmentos?
O que eu quero - espessura da linha variável, com linhas intrusivas dentro da silhueta ...
O que eu não quero ...
EDIT: Mais pesquisas mostraram o seguinte ...
Como eu tenho uma grande contagem de vértices no terreno, mesmo considerando o LoD baseado em distância, nem os normais invertidos nem uma abordagem baseada em sombreamento de geometria (mesmo com a seleção de frustum) seriam uma opção sensata devido à pura complexidade computacional envolvida na duplicação e dimensionamento de todos vértices enviados.
Considerando que eu não preciso de iluminação por pixel na forma de sombreamento de tom sólido nas superfícies do terreno, também se torna menos prudente considerar qualquer abordagem baseada na face normal - caso contrário, um requisito para a iluminação correta da superfície - como essas são naturalmente muito caros de calcular. No entanto, é verdade que eles dão o melhor grau de controle; por exemplo, a capacidade de sombrear arestas usando traços "artísticos": bonito, mas, novamente, não é realmente viável para um ambiente de jogo extremamente complexo.
Buffers de estêncil são algo que eu preferiria evitar, pois eu preferiria fazer todo o trabalho em shaders. (O exemplo acima, com o contorno vermelho, foi feito com um buffer de estêncil - old school.)
Isso deixa abordagens de espaço de imagem de shader fragment. A complexidade computacional é reduzida ao número de fragmentos e não ao número de vértices (no meu caso, são 10 a 100 vezes menos operações do que eu teria que fazer no sombreador de geometria). Isso requer mais de uma passagem de renderização para gerar um buffer g (que consiste em um buffer normal e opcionalmente também em um buffer de profundidade) ao qual podemos aplicar filtros de descontinuidade (por exemplo, operador Sobel). A descontinuidade em profundidade é o que permite contornos e vincos sugestivos. Meu único problema com essa abordagem é a incapacidade de fornecer um controle mais refinado sobre larguras de bordas com tinta, embora com o algoritmo correto no shader de fragmento, tenho certeza de que isso seria possível.
Portanto, a pergunta agora se torna mais específica: como exatamente eu obteria larguras de arestas variáveis, particularmente na silhueta externa, em um shader de fragmento?