capítulos 5 a 7 - pt

pull/272/head
rnbastos 5 years ago
parent f6c1020174
commit b227703343

@ -0,0 +1,140 @@
# Desenho algorítmico
## Funções de formas
Este capítulo poderia ser chamado de "lição da cerca do sr. Miyagi". Anteriormente, nós mapeamos a posição normalizada de *x* e *y* para os canais *red* e *green*. Essencialmente, fizemos uma função que recebe um vetor de duas dimensões (x e y) e retorna um de quatro dimensões (r, g, b e a). Mas, antes de seguirmos em frente e transformar dados entre as dimensões, precisamos começar de modo mais simples... muito mais simples. Isso significa entender como fazer uma função dimensional. Quanto mais energia e tempo você gastar aprendendo isso, mais forte vai seu karate-shader será.
![The Karate Kid (1984)](mr_miyagi.jpg)
A estrutura de código a seguir vai ser a sua cerca. Nele, visualizamos o valor normalizado da coordenada *x* (`st.x`) de duas formas: uma com brilho (observe o gradiente legal, do preto até o branco) e a outra, plotando uma linha verde no topo (nesse caso, o valor *x* é associado diretamente para o valor *y*). Não foque muito na função de plotagem, nós vamos entrar nela com mais detalhes em breve.
<div class="codeAndCanvas" data="linear.frag"></div>
**Nota Rápida**: O construtor do tipo `vec3` "entende" que você quer definir os três canais de cores com o mesmo valor, enquanto o `vec4` entende que você quer construir um vetor de quatro dimensões, com um vetor de três mais um quarto valor (neste caso o valor que controla o valor de alpha ou opacidade). Veja por exemplo as linhas 20 e 26 acima.
Este código é sua cerca; é importante observá-lo e entendê-lo. Você vai voltar várias vezes a esse espaço entre *0.0* e *1.0*. Você vai se especializar na arte de misturar e dar forma a essa linha.
Esta relação de um para um entre *x* e *y* (ou o brilho) é conhecida como *interpolação linear*. Daqui podemos usar algumas funções matemáticas para dar *forma* à linha. Por exemplo, podemos aumentar *x* à potência de 5 para criar uma linha *curva*.
<div class="codeAndCanvas" data="expo.frag"></div>
Interessante, certo? Na linha 22, tente expoentes diferentes: 20.0, 2.0, 1.0, 0.0, 0.2 e 0.02 por exemplo. Entender essa relação entre o valor e o expoente vai ser muito útil. Usando esses tipos de funções matemáticas aqui e ali vai dar a você um controle expressivo sobre seu código, um tipo de acupuntura de dados que permite controlar o fluxo de valores.
[`pow()`](../glossary/?search=pow) é uma função nativa em GLSL e existem muitas outras. A maioria delas são aceleradas a nível de hardware, o que significa que se elas forem usadas do modo certo, e com discrição, elas vão tornar seu código mais rápido.
Troque a função de potência na linha 22. Tente outras, como: [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log) e [`sqrt()`](../glossary/?search=sqrt). Algumas dessas funções são mais interessantes quando você brinca com elas usando PI. Você pode ver, na linha 8, que eu defini uma macro que vai substituir toda chamada a `PI` com o valor `3.14159265359`.
### Step e Smoothstep
GLSL também tem algumas funções únicas nativas de interpolação, aceleradas por hardware.
A interpolação [`step()`](../glossary/?search=step) recebe dois parâmetros. O primeiro é o limite ou threshold, enquanto o segundo é o valor que nós queremos checar ou passar. Qualquer valor abaixo do limite vai retonar `0.0` e tudo acima do limite retornará `1.0`.
Tente mudar esse valor de limite na linha 20 do código acima.
<div class="codeAndCanvas" data="step.frag"></div>
A outrao função é conhecida como [`smoothstep()`](../glossary/?search=smoothstep). Dado um range de dois números e um valor, esta função vai interpolar o valor entre o range definido. Os dois primeiros parâmetros são o começo e o fim da transição, e o terceiro é o valor a interpolar.
<div class="codeAndCanvas" data="smoothstep.frag"></div>
No exemplo anterior, na linha 12, note que usamos o smoothstep para desenhar a linha verde na função `plot()`. Para cada posição ao longo do eixo *x* essa função faz um *bump* em determinado valor de *y*. Como? Conectando dois [`smoothstep()`](../glossary/?search=smoothstep). Dê uma olhada na seguinte função, substitua pela linha 20 acima e pense nela como um corte vertical. O fundo parece uma linha, certo?
```glsl
float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x);
```
### Seno e Cosseno
Quando você quer usar matemática para animar, dar forma ou misturar valores, não há nada melhor que ser amigo do seno e cosseno.
Essas duas funções trigonométricas básicas trabalham juntas para construir círculos que são tão úteis quanto o canivete suíço do MacGyver. É importante saber como elas se comportam e de que maneiras podem ser combinadas. Em resumo, dado um ângulo (em radianos) elas vão retornar o posição correta de *x* ([cosine](../glossary/?search=cos)) e *y* ([sine](../glossary/?search=sin)) de um ponto na borda do círculo com raio igual a 1. Mas, o fato de que elas retornam valores normalizados (entre -1 e 1) de forma tão suave, faz com que sejam uma ferramenta incrível.
![](sincos.gif)
Ainda que seja difícil descrever todas as relações entre as funções trigonométricas e os círculos, a animação acima faz um belo trabalho de sumarizar essas relações visualmente.
<div class="simpleFunction" data="y = sin(x);"></div>
Dê uma olhada com atenção nessa onda do seno. Note como os valores *y* fluem suavemente entre +1 e -1. Como vimos no exemplo do tempo no capítulo anterior, você pode usar esse comportamento rítmico do [`sin()`](../glossary/?search=sin) para animar propriedades. Se você está lendo esse exemplo no browser, vai ver que pode mudar o código na fórmula acima para observar como a onda muda. OBS.: não se esqueça do ponto e vírgula no fim das linhas.
Tente os exercícios seguintes veja o que acontece:
* Adicione o tempo (`u_time`) ao *x* antes de calcular o `seno`. Internalize o **movimento** ao longo de *x*.
* Multiplique *x* por `PI` antes de calcular o `seno`. Note como as duas fases **encolhem** de modo que cada ciclo se repete a cada 2 inteiros.
* Multiplique o tempo (`u_time`) por *x* antes de calcular o `seno`. Veja como a frequência **frequency** entre as fases se torna mais e mais comprimida. Note que u_time pode já ter se tornado muito grande, fazendo o gráfico difícil de ler.
* Adicione 1.0 ao [`sin(x)`](../glossary/?search=sin). Veja como a onda inteira fica **deslocada** pra cima, e como todos os valores ficam entre 0.0 e 2.0.
* Multiplique [`sin(x)`](../glossary/?search=sin) por 2.0. Note como a **amplitude** dobra de tamanho.
* Compute o valor absoluto ([`abs()`](../glossary/?search=abs)) de `sin(x)`. Parece com o rastro de uma bola **saltitante**.
* Extraia apenas a parte fracionária ([`fract()`](../glossary/?search=fract)) do resultado de [`sin(x)`](../glossary/?search=sin).
* Adicione o maior inteiro ([`ceil()`](../glossary/?search=ceil)) e o menor ([`floor()`](../glossary/?search=floor)) do resultado de [`sin(x)`](../glossary/?search=sin) para obter uma onda digital de valores 1 e -1.
### Algumas funções extras úteis
No fim do último exercício, nós introduzimos algumas novas funções. Agora é hora de experimentas com cada uma, descomentando as linhas abaixo, uma de cada vez. Conheça essas funções e estude como elas se comportam. Eu sei, você está se perguntando... por queê? Uma pesquisa rápida no google sobre "arte generativa" ("generative art") vai te dizer. Tenha em mente que essas funções são nossa cerca. Estamos nos especializando no movimento em uma dimensão, para cima e para baixo. Logo será a hora para duas, três e quatro dimensões!
![Anthony Mattox (2009)](anthony-mattox-ribbon.jpg)
<div class="simpleFunction" data="y = mod(x,0.5); // retorna x módulo de 0.5
//y = fract(x); // retorna somente a parte fracionária de um número
//y = ceil(x); // o inteiro mais próximo que seja maior ou igual de x
//y = floor(x); // o inteiro mais próximo que seja menor ou igual de x
//y = sign(x); // extrai o sinal de x
//y = abs(x); // retorna o valor absoluto de x
//y = clamp(x,0.0,1.0); // restringe x para ficar entre 0.0 e 1.0
//y = min(0.0,x); // retorna o menor, x ou 0.0
//y = max(0.0,x); // retorna o maior, x ou 0.0 "></div>
### Funções de forma avançadas
[Golan Levin](http://www.flong.com/) tem uma grande documentação sobre funções de forma mais complexas que são extraordinariamente úteis. Portá-las para o GLSL é um movimento bem esperto, para começar a construir seus próprios recursos de pedaços de código.
* Funções de Forma - Polinomiais: [www.flong.com/texts/code/shapers_poly](http://www.flong.com/texts/code/shapers_poly/)
* Funções de Forma - Exponenciais: [www.flong.com/texts/code/shapers_exp](http://www.flong.com/texts/code/shapers_exp/)
* Funções de Forma - Circulares e Elípticas: [www.flong.com/texts/code/shapers_circ](http://www.flong.com/texts/code/shapers_circ/)
* Funções de Forma - Bezier e outras formas paramétricas: [www.flong.com/texts/code/shapers_bez](http://www.flong.com/texts/code/shapers_bez/)
<div class="glslGallery" data="160414041542,160414041933,160414041756" data-properties="clickRun:editor,hoverPreview:false"></div>
Como os chefs que colecionam temperos e ingredientes exóticos, os artistas digitais e programadores criativos têm um amor particular em trabalhar em suas próprias funções de forma.
[Iñigo Quiles](http://www.iquilezles.org/) tem uma grande coleção de [funções úteis](http://www.iquilezles.org/www/articles/functions/functions.htm). Depois de ler [este artigo](http://www.iquilezles.org/www/articles/functions/functions.htm) veja a seguinte tradução dessas funções para o GLSL. Preste atenção nas pequenas alterações necessárias, como colocar o "." (ponto) nos números de ponto flutuante e usar os nomes GLSL para as *funções C*; por exemplo, ao invés de usar `powf()`, use `pow()`:
<div class="glslGallery" data="05/impulse,05/cubicpulse,05/expo,05/expstep,05/parabola,05/pcurve" data-properties="clickRun:editor,hoverPreview:false"></div>
Para manter sua motivação em alta, aqui está um exemplo elegante (feito pelo [Danguafer](https://www.shadertoy.com/user/Danguafer)) para aumentar suas habilidades no karate das funções de formas.
<iframe width="800" height="450" frameborder="0" src="https://www.shadertoy.com/embed/XsXXDn?gui=true&t=10&paused=true" allowfullscreen></iframe>
No *Próximo >>* capítulovamos começar a usar nossos novos movimentos. Primeiro, misturando cores, e então desenhando formas.
#### Exercício
Dê uma olhada na tabela a seguir, com equações, feita por [Kynd](http://www.kynd.info/log/). Veja como ele está combinando funções e suas propriedades para controlar os valores entre 0.0 e 1.0. Agora é hora de você praticar, replicando essas funções. Lembre-se de que quanto mais você praticar, melhor vai ser o seu karatê.
![Kynd - www.flickr.com/photos/kynd/9546075099/ (2013)](kynd.png)
#### Para sua caixa de ferramentas
Aqui estão algumas ferramentas que vão fazer mais fácil você a visualizar esses tipos de funções.
* Grapher: se você tem um computador com MacOS, digite `grapher` no spotlight e você vai poder usar essa ferramentas super útil.
![OS X Grapher (2004)](grapher.png)
* [GraphToy](http://www.iquilezles.org/apps/graphtoy/): de novo [Iñigo Quilez](http://www.iquilezles.org) fez uma ferramenta para visualizar funções GLSL em WebGL.
![Iñigo Quilez - GraphToy (2010)](graphtoy.png)
* [Shadershop](http://tobyschachman.com/Shadershop/): essa ferramenta fantástica criada por [Toby Schachman](http://tobyschachman.com/) vai te ensinar como construir funções complexas, de uma maneira incrível, intuitiva e visual.
![Toby Schachman - Shadershop (2014)](shadershop.png)

@ -0,0 +1,145 @@
![Paul Klee - Color Chart (1931)](klee.jpg)
## Cores
Não tivemos muita chance de conversar sobre os tipos de vetores GLSL. Antes de avançar, é importante aprender mais sobre essas variáveis e o assunto das cores é uma boa forma de descobrir mais sobre eles.
Se você é familiar com os paradigmas da programação orientada a objetos, provavelmente notou que estamos acessando os dados dentro dos vetores como qualquer `struct` regular do C.
```glsl
vec3 red = vec3(1.0,0.0,0.0);
red.x = 1.0;
red.y = 0.0;
red.z = 0.0;
```
Definir uma cor usando uma notação *x*, *y* e *z* pode ser confuso e levar a erros, certo? É por isso que existem outras formar de acessar essa mesma informação, mas com nomes diferentes. Os valores de `.x`, `.y` e `.z` podem ser chamados de `.r`, `.g` e `.b`, e `.s`, `.t` and `.p`. (`.s`, `.t` e `.p` geralmente são usados para coordenadas espaciais de uma textura, o que vamos ver em um capítulo mais pra frente). Você também pode acessar os dados num vetor usando um índice de posições, `[0]`, `[1]` e `[2]`.
As seguintes linhas mostram todos os modos de acessar o mesmo dado:
```glsl
vec4 vector;
vector[0] = vector.r = vector.x = vector.s;
vector[1] = vector.g = vector.y = vector.t;
vector[2] = vector.b = vector.z = vector.p;
vector[3] = vector.a = vector.w = vector.q;
```
Essas maneiras diferentes de apontar para as variáveis dentro de um vetor são apenas nomenclaturas projetadas para te ajudar a escrever um código mais claro. Essa flexibilidade, embutida na linguagem, é uma porta para você começar a pensar em cores e coordenadas espaciais como intercambiáveis.
Uma outra grande característica de tipos de vetores em GLSL é que as propriedades podem ser combinadas em qualquer forma que quiser, o que torna mais fácil realizar cast e misturar valores. Essa habilidade é chamada de *swizzle*.
```glsl
vec3 yellow, magenta, green;
// Fazendo o Amarelo
yellow.rg = vec2(1.0); // Definindo 1. para os canais red e green
yellow[2] = 0.0; // Definindo 0. para o blue
// Fazendo o Magenta
magenta = yellow.rbg; // Definindo os canais com green e blue trocados
// Fazendo o Verde
green.rgb = yellow.bgb; // Definindo o canal blue do Yellow (0) para os canais red e blue
```
#### Para sua caixa de ferramentas
Você pode não ser acostumado a escolher cores com números - pode ser muito contra-intuitivo. Para sua sorte, há muitos programas que tornam esse um trabalho fácil. Encontre um que se encaixe às suas necessidades e então treine-o para entregar cores no formato `vec3` ou `vec4`. Por exemplo, aqui estão os templates que uso no [Spectrum](http://www.eigenlogik.com/spectrum/mac):
```
vec3({{rn}},{{gn}},{{bn}})
vec4({{rn}},{{gn}},{{bn}},1.0)
```
### Misturando cores
Agora que você já sabe como as cores são definidas, é hora de integrar isso com o que já sabemos. Em GLSL, existe uma função muito útil, [`mix()`](../glossary/?search=mix), que te permite mixar dois valores em porcentagens. Adivinha qual é o range de valores para a porcentagem? Sim, valores entre 0.0 e 1.0! Isso é perfeito para você, depois daquelas horas todas praticando seus movimentos de karatê com a cerca - é hora de usá-los!
![](mix-f.jpg)
Verifique o seguinte código na linha 18, veja como estamos usando os valores absolutos de uma onda senóide ao longo do tempo para mixar `colorA` e `colorB`.
<div class="codeAndCanvas" data="mix.frag"></div>
Demonstre suas habilidades, fazendo isso:
* Faça uma transição expressiva entre as cores. Pense numa emoção particulas. Que cor parace mais representar isso? Como ela aparece? Como ela desaparece? Pense em outra emoção e cores que combinam. Mude a cor do início e do fim do código acima, para combinar com essas emoçoes. Então, anime a transição usando funções de forma. Robert Penner desenvolveu uma série de funções de forma populares para animação em computadores, conhecida como [facilitando funções](http://easings.net/), você pode usar [este exemplo](../edit.php#06/easing.frag) como pesquisa e inspiração mas o melhor resultado virá com você fazendo suas próprias transições.
### Brincando com gradientes
A função [`mix()`](../glossary/?search=mix) tem mais a oferecer. Ao invés de um único simples `float`, podemos passar um tipo de variável que combine com os dois primeiros argumentos, em nosso caso um `vec3`. Fazendo isso, ganhamos controle sobre as porcentagens de mistura de cada canal individualmente, `r`, `g` e `b`.
![](mix-vec.jpg)
Dê uma olhada no exemplo a seguir. Como nos exemplos do capítulo anterior, estamos ligando a transição Às coordenada *x* normalizada e visualizando-a com uma linha. Nesse momento, todos os canais vão na mesma linha.
Agora, descomente a linha 25 e veja o que acontece. Então, tente descomentar as linhas 26 e 27. Lembre que as linhas visualizam a quantidade de `colorA` e `colorB` para misturar por canal.
<div class="codeAndCanvas" data="gradient.frag"></div>
Você deve ter reconheido as três funções de forma que estamos usando nas linhas 25 a 27. Brinque com elas! É hora de você explorar e exibir suas habilidades do capítulo anterior e fazer uns gradientes interessantes. Tente os seguintes exercícios:
![William Turner - The Fighting Temeraire (1838)](turner.jpg)
* Compor um gradiente que se pareça com o pôr do sol do William Turner
* Animar uma transição entre um nascer e um pôr do sol, usando `u_time`.
* Você consegue fazer um arco-íris com o que aprendemos até agora?
* Use a função `step()` para criar uma bandeira colorida.
### HSB
Não podemos falar de cores sem falar no espaço de cores. Como você deve saber, existem modos diferentes de organizar as cores, além dos canais de vermelho, verde e azul.
[HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) significa Matix(Hue), Saturação e Brilho (ou Valor) e é uma organização mais intuitiva e útil para as cores. Tire um momento para ler as funções `rgb2hsv()` e `hsv2rgb()` no código a seguir.
Mapeando a posição no eixo x para Matiz, e a posiçãono eixo y para o Brilho, obtemos um bom espectro de cores visíveis. Esta distribuição espacial da cor pode ser bem interessante de se ter à mão; é mais intuitivo pegar uma cor com HSB do que com RGB.
<div class="codeAndCanvas" data="hsb.frag"></div>
### HSB em coordenadas polares
O HSB foi projetado originalmente para ser representados em coordenadas polares (baseadas em ângulo e raio) em vez de coordenadas cartesianas (baseadas em x e y). Para mapear nossa função HSB para coordenadas polares, precisamos obter o ângulo e distância do centro da tela até a coordenada do pixel. Para isso, usamos as funções [`length()`](../glossary/?search=length) e [`atan(y,x)`](../glossary/?search=atan) (que é a versão GLSL da função comumente usada `atan2(y,x)`).
Quando você usa funções de vetores e trigonométricas, `vec2`, `vec3` e `vec4` são tratados como vetores mesmo quando eles representam cores. Vamos começar a tratar cores e vetores de modo similar, e de fato você vai descobrir que essa flexibilidade conceitual traz muito poder.
**Nota:** Se você está se perguntando, existem mais funções geométricas além de [`length`](../glossary/?search=length) como: [`distance()`](../glossary/?search=distance), [`dot()`](../glossary/?search=dot), [`cross`](../glossary/?search=cross), [`normalize()`](../glossary/?search=normalize), [`faceforward()`](../glossary/?search=faceforward), [`reflect()`](../glossary/?search=reflect) e [`refract()`](../glossary/?search=refract). GLSL também tem funções relacionais especiais para vetores, como: [`lessThan()`](../glossary/?search=lessThan), [`lessThanEqual()`](../glossary/?search=lessThanEqual), [`greaterThan()`](../glossary/?search=greaterThan), [`greaterThanEqual()`](../glossary/?search=greaterThanEqual), [`equal()`](../glossary/?search=equal) e [`notEqual()`](../glossary/?search=notEqual).
Uma vez que obtivemos o ângulo e tamanho, temos que "normalizar" os valores para o range entre 0.0 e 1.0. Na linha 27, [`atan(y,x)`](../glossary/?search=atan) vai retornar um ângulo em radianos, entre -PI e PI (-3.14 to 3.14), então temos que dividir esse número por `TWO_PI` (definido no início do código) para chegar a valores entre -0.5 e 0.5, que, por simples adição, mudamos para o range desejado de 0.0 a 1.0. O raio vai retornar um valor máximo de 0.5 (porque estamos calculando a distância do cento da tela), então precisamos dobrar esse range (multiplicando por dois) para ter o máximo de 1.0.
Como pode ver, nosso jogo aqui é transformar e mapear ranges para o range de 0.0 a 1.0 que nós gostamos.
<div class="codeAndCanvas" data="hsb-colorwheel.frag"></div>
Tente os seguintes exercícios:
* Modifique o exemplo polar para conseguir uma roda de cores girando, parecido com o ícone de espera do mouse.
* Use uma função de forma junto com a de conversão de HSB para RGB para expandir um valor de matiz particular e encolher o resto.
![William Home Lizars - Red, blue and yellow spectra, with the solar spectrum (1834)](spectrums.jpg)
* Se você olhar bem de perto na roda de cores usada nos selecionadores (ver a imagem acima), eles usam um espectro diferente de acordo com o espaço de cores RYB. por exemplo, a cor oposta ao vermelho deveria ser o verde, mas no nosso exemplo é o ciano. Você consegue achar um jeito de consertar isso, de modo a ficar parecendo exatamente igual à imagem seguinte? [Dica: esse é um bom momento para usar funções de forma.]
![](colorwheel.png)
* Leia o [livro Interaction of Color do Josef Albers'](http://www.goodreads.com/book/show/111113.Interaction_of_Color) e use os seguintes exemplos de shaders como prática.
<div class="glslGallery" data="160505191155,160505193939,160505200330,160509131554,160509131509,160509131420,160509131240" data-properties="clickRun:editor,openFrameIcon:false,showAuthor:false"></div>
#### Nota sobre funções e argumentos
Antes de pular para o próximo capítulo, vamos parar e recapitular. Volte e dê uma olhada nas funções nos exemplos anteriores. Você vai notar o `in` antes do tipo dos argumentos. Isso é um [*qualificador*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier) e nesse caso, ele especifica que a variável é somente de leitura. Em exemplos futuros, vamos ver que é possível definir argumentos como `out` ou `inout`. Esse último, `inout`, é conceitualmente similar a passar um argumento por referência, que vai nos dar a possibilidade de modificar uma variável passada.
```glsl
int newFunction(in vec4 aVec4, // read-only
out vec3 aVec3, // write-only
inout int aInt); // read-write
```
Você pode não acreditar, mas agora temos todos os elementos para fazer desenhos legais. No próximo capítulo, vamos aprender como combinar todos os nossos truques para fazer formar geométricas fazendo um *blend* (misturando) o espaço. Sim... *blend* no espaço.

@ -0,0 +1 @@
Familiarize-se com o modo de se expressar em cores nos shaders. Os exemplos cobrem a maneira de misturar cores e animá-las lindamente ao longo do tempo, bem como a conversão entre dois modelos diferentes (RGB e HSB). Em GLSL, as cores são simplesmente como vetores, o que quer dizer que você pode facilmente aplicar os conceitos e técnicas que aprender aqui para outros.

@ -0,0 +1 @@
## Cores

@ -0,0 +1,231 @@
![Alice Hubbard, Providence, United States, ca. 1892. Photo: Zindman/Freemont.](froebel.jpg)
## Formas
Finalmente! A gente vem construindo habilidades para este momento! Você aprendeu a maioria das fundações, tipo s funções GLSL. Você praticou suas equações de formas várias vezes. Agora é a hora de juntar tudo. Você está pronto para este desafio! Neste capítulo, vai aprender como desenhar formas simples, de forma procedural paralela.
### Retângulo
Imagine que tenhamos um papel quadriculado como os que usamos nas aulas e exercícios de casa de matemática, e queremos desenhar um quadrado. O tamanho do papel é 10x10 e o quadrado deveria ser 8x8. O que você vai fazer?
![](grid_paper.jpg)
Você pintaria tudo, menos a primeira linha e a última, e a primeira coluna e a última, certo?
E como isso se relaciona com os shaders? Cada quadradinho de nosso papel é uma thread (um pixel). Cada quadradinho sabe sua posição, como as coordenadas de um tabuleiro de xadrez. Em capítulos anteriores, nós mapeamos *x* e *y* para os canais de cores *vermelho* e *verde*, e aprendemos como usar o estreito território bidimensional entre 0.0 e 1.0. Como podemos usar isso para desenhar um quadrado centralizado no meio da nossa tela?
Vamos começar rascunhando um pseudocódigo que usa vários `if` no campo espacial. Os princípios para fazer isso são notavelmente similares ao modo que pensamos no cenário do papel quadriculado.
```glsl
if ( (X MAIOR QUE 1) AND (Y MAIOR QUE 1) )
pinta de branco
else
pinta de preto
```
Agora que temos uma ideia melhor de como isos vai funcionar, vamos substituir os `if` com [`step()`](../glossary/?search=step), e, em vez de usar 10x10, vamos usar valores normalizados entre 0.0 e 1.0:
```glsl
uniform vec2 u_resolution;
void main(){
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(0.0);
// Cada resultado retorna 1.0 (branco) ou 0.0 (preto).
float left = step(0.1,st.x); // Similar a ( X maior que 0.1 )
float bottom = step(0.1,st.y); // Similar a ( Y maior que 0.1 )
// A multiplicação left*bottom vai ser similar ao AND lógico.
color = vec3( left * bottom );
gl_FragColor = vec4(color,1.0);
}
```
A função [`step()`](../glossary/?search=step) vai tornar cada pixel abaixo de 0.1 preto (`vec3(0.0)`) e o resto branco (`vec3(1.0)`) . A multiplicação entre `left` e `bottom` funciona como um `AND` lógico, onde os dois devem estar 1.0 para retornar 1.0. Isso desenha duas linhas pretas, uma no fundo, e outra na lado esquerdo do canvas.
![](rect-01.jpg)
No código anterior, repetimos a estrutura para cada eixo (esquerdo e fundo). Podemos economizar algumas linhas de código, passando 2 vaores diretamente para [`step()`](../glossary/?search=step) ao invés de apenas um. Seria algo assim:
```glsl
vec2 borders = step(vec2(0.1),st);
float pct = borders.x * borders.y;
```
Até agora, só desenhamos duas bordar (fundo-esquerda) de nosso retângulo. Vamos desenhar as outras duas (topo-direita). Veja esse código:
<div class="codeAndCanvas" data="rect-making.frag"></div>
Descomente as *linhas 21-22* e veja como invertemos as coordenadas `st` e repetimos a mesma função [`step()`](../glossary/?search=step). Desse jeito, o `vec2(0.0,0.0)` vai estar no canto superior direito. Isso é o equivalente digital a girar a página e repetir o mesmo procedimento.
![](rect-02.jpg)
Note que nas *linhas 18 e 22*, todos os lados estão sendo multiplicados juntos. É o mesmo que escrever:
```glsl
vec2 bl = step(vec2(0.1),st); // bottom-left
vec2 tr = step(vec2(0.1),1.0-st); // top-right
color = vec3(bl.x * bl.y * tr.x * tr.y);
```
Interessante, certo? Essa técnica é, basicamente, usar [`step()`](../glossary/?search=step) e multiplicação para operações lógicas, e flipar as coordenadas.
Antes de prosseguir, tente os exercícios a seguir:
* Mude o tamanho e as proporções do retângulo.
* Experimente com o mesmo código, mas usando [`smoothstep()`](../glossary/?search=smoothstep) no lugar de [`step()`](../glossary/?search=step). Note que, ao mudar os valores, você pode ir de beiradas embaçadas até elegantes bordas suaves.
* Faça uma outra implementação que use [`floor()`](../glossary/?search=floor).
* Escolha a implementação de que gostar mais, e faça uma função dela, que você possa reutilizar no futuro. Deixe sua função flexível e eficiente.
* Faça outra função que apenas desenhe o contorno do retângulo.
* Como você acha que poderia mover e colocar retângulos diferentes na mesma tela? Se descobrir como, mostre suas habilidades fazendo uma composição de retângulos e cores que se pareça com uma pintura de [Piet Mondrian](http://en.wikipedia.org/wiki/Piet_Mondrian).
![Piet Mondrian - Tableau (1921)](mondrian.jpg)
### Círculos
É fácil desenhar quadrados em um papel quadriculado, e retângulos em coordenadas cartesianas, mas círculos requerem outra abordagem, especialmente porque precisamos de um algoritmo "por pixel". Uma solução é *remapear* as coordenadas espaciais de modo que possamos usar uma função [`step()`](../glossary/?search=step) para desenhar um círculo.
Como? Vamos começar, voltando um pouco às aulas de matemática e o papel quadriculado, onde nós abríamos um compasso até o raio do círculo, apertamos uma das pontas do compasso no centro do círculo, e então tracejamos o contorno do círculo com uma rodada do compasso.
![](compass.jpg)
Traduzindo isso para um shader, onde cada quadrado no papel é um pixel, implica em *perguntar* a cada pixel (ou thread) se ele está dentro da área do círculo. Fazemos isso calculando a distância do pixel até o centro do círculo.
![](circle.jpg)
Existem várias formas de se calcular essa distância. A mais fácil usa a função [`distance()`](../glossary/?search=distance), que, internamente, calcula o [`length()`](../glossary/?search=length) (comprimento) da diferença entre dois pontos (em nosso caso, a coordenada do pixel, e o centro da tela). A função `length()` nada mais é que um atalho para a [equação de hipotenusa](http://en.wikipedia.org/wiki/Hypotenuse) que usa raiz quadrada ([`sqrt()`](../glossary/?search=sqrt)) internamente.
![](hypotenuse.png)
Você pode usar [`distance()`](../glossary/?search=distance), [`length()`](../glossary/?search=length) ou [`sqrt()`](../glossary/?search=sqrt) para calcular a distância até o centro da tela. O código a seguir contém essas três funções e o fato não-surpreendente de que retornam o mesmo resultado.
* Comente e descomente as linhas para testar as diferentes formar de obter o mesmo resultado.
<div class="codeAndCanvas" data="circle-making.frag"></div>
No exemplo anterior, nós mapeamos a distância até o centro para o brilho da cor de cada pixel. Quanto mais ao centro está um pixel, mais escuro ele é (menor valor de cor). Note que os valores não ficam muito altos porque a partir do centro ( `vec2(0.5, 0.5)` ) a distância máxima mal passa de 0.5. Contemple esse mapa e pense:
* O que você pode inferir disso?
* Como podemos usar isso para desen um círculo?
* Modifique o código acima, de modo a conter o gradiente circular inteiro dentro do canvas.
### Campo de distância
Também podemos pensar no exemplo acima como um mapa de altitude, onde áreas mais escuras implicam em maior altura. O gradiente nos mostra algo similar ao padrão feito por um cone. Imagine-se no topo desse cone. A distância horizontal até a borda do cone é 0.5. Isso será constante em todas as direções. Escolhendo onde "cortar" o cone, vai te dar uma superfície circular maior ou menor.
![](distance-field.jpg)
Basicamente, estamos usando uma reinterpretação do espaço (baseado na distância até o centro) para fazer formas. Essa técnica é conhecida como "campo de distância" e é usada e diferentes modos, desde outlines de fontes até gráficos 3D.
Tente os seguintes exercícios:
* Use o [`step()`](../glossary/?search=step) para tornar tudo acima de 0.5 em branco e tudo abaixo para 0.0.
* Inverta as cores do fundo e do primeiro plano.
* Usando [`smoothstep()`](../glossary/?search=smoothstep), faça experiências com valores diferentes para conseguir uma borda suave no seu círculo.
* Uma vez que esteja feliz com uma implementação, faça uma função com ela, para reutilizar no futuro.
* Adicione cor ao círculo.
* Você pode animar seu círculo, para crescer e encolher, simulando a batida de um coração? (Você pode ter alguma inspiração, da animação do capítulo anterior)
* Que tal mover esse círculo? Você consegue movê-lo para lugares diferentes na tela?
* O que acontece se você combinar campos de distância usando diferentes funções e operações?
```glsl
pct = distance(st,vec2(0.4)) + distance(st,vec2(0.6));
pct = distance(st,vec2(0.4)) * distance(st,vec2(0.6));
pct = min(distance(st,vec2(0.4)),distance(st,vec2(0.6)));
pct = max(distance(st,vec2(0.4)),distance(st,vec2(0.6)));
pct = pow(distance(st,vec2(0.4)),distance(st,vec2(0.6)));
```
* Faça três composições usando essa técnica. Se forem animadas, melhor ainda!
#### Para sua caixa de ferramentas
Em termos de poder computacional, a função [`sqrt()`](../glossary/?search=sqrt) - e todas as que dependem dela - pode ser bem cara. Aqui vai outra forma de criar um campo de distância usando [`dot()`](../glossary/?search=dot) (produto escalar).
<div class="codeAndCanvas" data="circle.frag"></div>
### Propriedades úteis de um Campo de Distância
![Zen garden](zen-garden.jpg)
Campos de Distância podem ser usados para desenhar quase tudo. Obviamente, quanto mais complexa for uma forma, mais complicada vai ser a equação, mas uma vez que você tenha a fórmula para fazer um campo de distância de uma forma específica, é muito fácil combinar e/ou aplicar efeitos a ela, como bordas suaves, e múltiplos outlines. Por causa disso, os campos de distância são populares para rendereizar fontes, como [Mapbox GL Labels](https://www.mapbox.com/blog/text-signed-distance-fields/), [Matt DesLauriers](https://twitter.com/mattdesl) [Material Design Fonts](http://mattdesl.svbtle.com/material-design-on-the-gpu) e [ como descrito no capítulo 7 do livro iPhone 3D Programming, OReilly](http://chimera.labs.oreilly.com/books/1234000001814/ch07.html#ch07_id36000921).
Dê uma olhada no código a seguir.
<div class="codeAndCanvas" data="rect-df.frag"></div>
Começamos movendo o sistema de coordenadas para o centro e encolhendo-o pela metade, para remapear os valores de posição entre -1 e 1. Também, na *linha 24*, estamos visualizando os valores do campo de distância usando uma função [`fract()`](../glossary/?search=fract) para facilitar que você veja o padrão que eles criam. O padrão do campo de distância se repete o tempo todo, como anéis num jardim Zen.
Vamos dar uma olhada na fórmula do campo, na *linha 19*. Ali, estamos calculando a distância até a posição `(.3,.3)` ou `vec3(.3)` em todos os nossos quatro quadrantes (é isso o que o [`abs()`](../glossary/?search=abs) está fazendo aqui).
Se você descomentar a *linha 20*, vai notar que estamos combinando as distâncias para esses quatro pontos usando o [`min()`](../glossary/?search=min) para zero. O resultado produz um novo padrão bem interessante.
Agora, tente descomentar a *linha 21*; estamos fazendo o mesmo, mas usando a função [`max()`](../glossary/?search=max). O rsultado é um retângulo com cantos arredondados. Note como os anéis do cmapo ditância ficam mais suaves quanto mais disntantes do centro.
Termine de descomentar as *linhas 27 a 29* uma a uma, para entender os diferentes usos de um padrão de campo de distância.
### Formas Polares
![Robert Mangold - Untitled (2008)](mangold.jpg)
No capítulo sobre sores, nós mapeamos as coordenadas cartesianas para coordenadas polares, calculando o *raio* e os *ângulos* de cada pixel com essa fórmula:
```glsl
vec2 pos = vec2(0.5)-st;
float r = length(pos)*2.0;
float a = atan(pos.y,pos.x);
```
Usamos parte desta fórmula no começo do capítulo para desenhar um círculo. Nós calculamos a distância até o centro usando [`length()`](../glossary/?search=length). Agora que sabemos sobre os os campos de distância, podemos aprender outra forma de desenhar formar, usando coordenadas polares.
Esta técnica é um pouco restritiva, mas bem simples. Ela consiste em mudar o raio de um círculo dependendo do ângulo, para obter formas diferentes. Como a modulação funciona? Sim, usando funções de formas!
Abaixo, você vai encontrar as mesmas funções do gráfico cartesiano e em um exemplo shader de coordenadas polares (entre as *linhas 21 e 25*). Descomente as funções uma a uma, prestando atenção na relação entre um sistema de coordenadas e o outro.
<div class="simpleFunction" data="y = cos(x*3.);
//y = abs(cos(x*3.));
//y = abs(cos(x*2.5))*0.5+0.3;
//y = abs(cos(x*12.)*sin(x*3.))*.8+.1;
//y = smoothstep(-.5,1., cos(x*10.))*0.2+0.5;"></div>
<div class="codeAndCanvas" data="polar.frag"></div>
Tente:
* Animar essas formas.
* Combinar funções de formas diferentes para *cortar buracos* na forma, para fazer flores, flocos de neve e engrenagens.
* Use a função `plot()` que usamos no capítulo sobre *Funções de Formas* para desenhar só o contorno.
### Combinando forças
Agora que aprendemos como modular o raio de um círculo de acordo com o ângulo, usando [`atan()`](../glossary/?search=atan) para desenhar formas diferentes, podemos aprender a usar `atan()` com campos de distância e aplicar todos os truques e efeitos possíveis com campos de distância.
O truque vai usar o número de lados de um polígono para construir o campo de distância, usando coordenadas polares. Veja o [seguinte código](http://thndl.com/square-shaped-shaders.html) do [Andrew Baldwin](https://twitter.com/baldand).
<div class="codeAndCanvas" data="shapes.frag"></div>
* Usando este exemplo, faça uma função que tem como entrada a posição e o número de lados de uma forma desejada, e retorna um valor de campo de distância.
* Misture campos de distância usando [`min()`](../glossary/?search=min) e [`max()`](../glossary/?search=max).
* Escolha um logo geométrico para replicar, usando campos de distância.
Parabéns! Você já passou pela parte mais dura! Dê uma pausa e deixe os conceitos assentarem - desenhar formas simples no Processing é fácil, mas não aqui. Na terra dos shaders, desenhar formas é difícil, e pode ser cansativo se adaptar a esse novo paradigma de programação.
Agora que você já sabe como desenhar formas, tenho certeza de que novas ideias vão pular na sua mente. No capítulo a seguir, você vai aprender como mover, rotacionar e mudar a escala das formas. Isso vai te permitir a fazer composições!

@ -0,0 +1 @@
Vamos dar uma olhada em como desenhar formar simples de forma procedural paralela. Em poucas palavras, tudo o que você precisa é determinar se cada pixel pertence à forma que quer desenhar ou não, e aplicar cores diferentes dependendo do caso. Você pode usar o sistema de coordenadas, como um papel quadriculado, para desenhar retângulos e quadrados. Vamos olhar um conceito mais avançado chamado campo de distância para desenhar formar mais complexas.

@ -0,0 +1 @@
## Formas
Loading…
Cancel
Save