Criar um efeito de lápis no SVG

Meu jogo Dragons Abound cria mapas em formato de gráficos vetoriais SVG. Os gráficos vetoriais têm muitos recursos (por exemplo, zoom sem perdas), o que é conveniente para mapas. Além disso, os gráficos vetoriais são bons para criar linhas nítidas, como contornos de tinta:


Por outro lado, os gráficos vetoriais não são muito bons na criação de texturas com pequenos detalhes não repetitivos. Nos gráficos vetoriais, cada elemento renderizado é representado por uma descrição de seu tamanho, forma, localização, cor etc. Para apresentar muitos pequenos detalhes não repetitivos, muitos elementos precisam ser descritos. Por exemplo, para uma linha de lápis


serão necessárias dezenas de milhares de elementos diferentes. De fato, cada ponto cinza da imagem será definido separadamente. Outros elementos, como imagens tremidas, são ainda mais problemáticas.

Essa é uma limitação bastante séria dos gráficos vetoriais; portanto, foram adicionados truques ao SVG que permitem reproduzir com mais eficiência alguns desses efeitos de textura. Explorarei alguns desses recursos SVG para criar um efeito de linha de lápis. Obviamente, existem muitas soluções mais complexas para recriar linhas de lápis. Artigos científicos inteiros foram escritos sobre este tópico . Mas só espero criar um filtro bastante simples que forneça um resultado aceitável.

Como sempre, eu preferiria emprestar ou modificar um filtro criado por alguém mais talentoso do que eu, mas nesse caso havia uma incrível escassez de filtros de lápis vetoriais que podem ser usados ​​como inspiração. (Uma música de aviso ameaçadora soa: pode haver razões para isso.) Portanto, de fato, só posso confiar em mim.

Anteriormente, eu escrevi sobre as possibilidades Dragons abundampara criar linhas "manuscritas". Basicamente, considerei a possibilidade de evitar linhas matematicamente retas e criar linhas com pequenos desvios que parecem mais próximos do que poderia ser desenhado pela mão de uma pessoa. No início do artigo, são mostrados exemplos de ilustrações de montanhas. Para criar um estilo de ilustração de tinta, isso é suficiente, mas não é adequado para criar uma linha de lápis, porque falta uma textura de lápis.

Se você observar as linhas de lápis mostradas acima e abaixo:


você notará muitos recursos que distinguem traços de lápis de linhas de tinta (ou linhas desenhadas por um computador). A diferença mais importante é que eles têm uma textura resultante da maneira como o lápis interage com o papel. O papel é granulado e o lápis geralmente deixa grafite nas partes altas do grão, enquanto as partes baixas permanecem brancas. Em papel grosso, a textura é mais visível; desenhar papelão é tão bom que quase não cria textura. Em segundo lugar, as bordas das linhas do lápis são bastante vagas. Isso se deve em grande parte à irregularidade do papel e à ponta do lápis; isso leva ao fato de que, ao longo da borda da linha, permanece uma quantidade diferente de grafite.

(Claro, há outros efeitos. O traço do lápis sobrepõe-se, por isso se torna mais escura nas intersecções dos cursos. Os traços si variam de pressão e isso pode mudar a escuridão do curso ao longo de seu comprimento. Neste post, vou me concentrar principalmente na reconstrução da textura do papel.)

Para Comecei preparando simples linhas cinzas:


Desenhei linhas "manuscritas" com espessura de 4, 2 e 1 pixel. Infelizmente, os efeitos SVG geralmente parecem diferentes para linhas de comprimentos diferentes, então eu queria comparar o efeito em tamanhos diferentes.

A principal função fornecida pelo SVG para adicionar efeitos de textura é chamada de filtros . Os filtros são aplicados após renderizar o efeito vetorial e alterar sua aparência. Os filtros convencionais podem executar ações como alterar a cor de um objeto, adicionar ruído a ele etc. Os filtros são um tópico bastante confuso, com sintaxe complexa, por isso não darei um tutorial completo sobre como usá-los, mas explicarei com detalhes suficientes para que fique claro o que fiz. E no final do post, darei um link para o Codepen com um filtro, para que você possa experimentar você mesmo.

Primeiramente, tentarei alterar as bordas das linhas para que não fiquem lisas, mas tenham irregularidades características do grão do papel. Farei isso movendo os pixels da linha. O elemento de filtro que executa esta tarefa é chamado "feDisplacementMap"; move cada pixel com base nos valores em outra imagem. Como queremos que cada pixel se mova de maneira aleatória, mas uniforme, precisamos passar o ruído para feDisplacementMap para controlar o movimento. Felizmente, o SVG possui outro elemento de filtro chamado "feTurbulence", projetado especificamente para criar ruído. Assim, podemos combinar dois filtros para tornar as bordas das linhas mais ásperas.

A magnitude e a aspereza da linha podem ser controladas pelos parâmetros do mapa de deslocamento e geração de ruído. Infelizmente, o deslocamento é indicado em unidades absolutas, não em relação ao tamanho da linha. Selecionei os parâmetros, tentando encontrar algo que se encaixa em todas as larguras de linha, mas com um aumento na escala de deslocamento, você pode perceber o problema:


Agora, o deslocamento é tão grande que pode mover toda a linha, e não apenas mudar suas arestas. Esse efeito é ainda mais visível em linhas finas. Neste exemplo, uma linha com uma largura de 4 pixels basicamente parece que a aresta é áspera e distorções já são evidentes em uma linha com uma espessura de 2 pixels. Ou seja, preciso escolher um valor que não crie distorções nas linhas finas.

Ao ampliar com um aumento padrão no jogo, o efeito se parece com o seguinte (após selecionar parâmetros para melhorar o efeito):


Nesta escala, muitas arestas ásperas se tornam pontos e pontos. Esse não é um efeito muito desagradável e lembra um pouco a linha de lápis. (No entanto, em geral, os filtros SVG parecem ter problemas com o dimensionamento - em muitos casos, quando ampliados, parecem bons, mas estão sujeitos a um algoritmo de redimensionamento ruim ao se afastar.)

Veja como é o efeito ao pintar montanhas (efeito lápis à esquerda):


Não é tão terrível, mas a linha tem artefatos afiados que parecem um pouco estranhos. E quando o efeito é aplicado a linhas finas e bem espaçadas, elas se sobrepõem e se fundem como resultado:


Repito, isso não é tão terrível, e as sombras nas montanhas de lápis são muito parecidas com as desenhadas por um lápis, se você precisar desse efeito.

Essa solução adiciona rugosidade aos contornos do traçado do lápis, mas não altera a cor uniforme do traçado. A textura também está presente nos traços reais do lápis, porque a grafite deixa manchas no papel de maneira desigual.

Para adicionar textura ao interior do traçado, eu uso um filtro SVG e depois combino o ruído com o traçado:


Quando ampliado, você pode ver que o interior de cada traçado agora está preenchido com uma textura de pseudo-grafite. Aqui está o que parece em uma escala normal:


Muito bom, especialmente em linhas grossas. Aqui está o que parece ao desenhar montanhas:


Nesta escala, tudo não é muito bom. Observe que esse filtro também reduz a escuridão das linhas; este é um resultado natural da adição de ruído branco às linhas. Até certo ponto, esse problema pode ser amenizado aumentando o contraste do ruído, para que algumas partes da linha de compensação fiquem mais escuras:


Mas como as cores da linha já são bastante escuras, isso destrói amplamente o efeito do "lápis". Portanto, se eu usar isso, preciso selecionar os parâmetros para criar um equilíbrio agradável.

Obviamente, ambas as soluções podem ser combinadas. Com um aumento, o resultado parece muito bom:


Da linha de lápis, esperamos uma borda áspera e uma textura interna. Em uma escala padrão, nem tudo é tão bom:


devido a artefatos afiados que apareceram nessa escala.

Um bom truque para melhorar essa textura seria adicionar textura de papel ao fundo:


Agora, o olho percebe a textura uniforme em toda a imagem. Mesmo em um nível muito implícito, isso ajuda a enganar os olhos e convencer que a textura da linha é causada pela interação com o papel.

Aqui está um exemplo de uso desse filtro em um mapa (com textura de papel):


Em geral, nem tudo está ruim, mas com um estudo detalhado parece que em todos os lugares apenas adicionamos ruído. Com um aumento de 200%, os artefatos se tornam ainda mais óbvios:


Outra maneira de criar uma aresta áspera de uma linha de lápis é desenhar a linha várias vezes com desvios ligeiramente diferentes e opacidade reduzida. No centro da linha, onde várias versões dela se cruzam, a densidade estará próxima da densidade da linha original; nas bordas externas, onde às vezes há apenas parte das linhas, a opacidade será mais baixa e as bordas serão menos legíveis.

Em geral, para implementar essa solução usando filtros SVG, é necessário usar feTurbulence e feDisplacementMap juntos para criar uma versão distorcida da linha. No entanto, para fazer isso várias vezes e combinar todas as linhas no final, você precisa de um conjunto de primitivas feBlend. Se, por exemplo, misturarmos três cópias, precisamos reduzir adequadamente a opacidade das linhas. (Não sei ao certo como calcular especificamente a opacidade correspondente, mas acho que ela pode ser a raiz do cubo da luminosidade da linha.)

Isso cria o efeito (três linhas com um aumento):


Essa abordagem tem algumas desvantagens. O filtro tem um desvio fixo, portanto, afeta linhas estreitas com mais força e, em alguns pontos, pode ser visto que a linha de pixel único está completamente dividida. Em segundo lugar, é um filtro bastante complexo que cria três desvios separados e os combina; pode ser muito lento em imagens complexas como cartões de Dragons Abound .

Aqui está o que parece em uma escala padrão:


Na minha opinião, isso não é exatamente como um esboço a lápis, mas elimina melhor os artefatos afiados da solução anterior.

Essa abordagem pode ser combinada com o filtro interno de texturas descrito acima e adicionar textura dentro das linhas do lápis, além da textura do papel:


Aqui está o que parece depois de aplicar nas montanhas:


Esse filtro tende a distribuir as linhas com mais força do que o outro filtro, essencialmente tornando-as mais espessas. Às vezes, gera um efeito de esboço com várias linhas, o que não é tão ruim.

Aqui está um exemplo do uso desse filtro em um mapa:


Ele preserva a escuridão original melhor do que o primeiro filtro e, embora na minha opinião não pareça exatamente um lápis, o efeito é bastante agradável. Com um aumento de 200%:


Quando ampliado, esse filtro não adquire artefatos nítidos do primeiro filtro. O efeito da interseção de linhas em linhas finas (por exemplo, como na imagem de uma floresta) começa a parecer bastante artificial, mas linhas mais largas (montanhas e rios) ainda parecem boas. No entanto, dentro das linhas pretas, como rios, o ruído interno é quase completamente perdido.

Postei esses dois filtros no Codepen para que você possa experimentá-los. O primeiro filtro está aqui , o segundo está aqui . Eu recomendo experimentar com eles e tentar melhorá-los, e se você conseguir algo melhor que o meu, me avise! Eu gostaria de ter um filtro de lápis muito bom!

All Articles