# Conflicts:
#	00/README-pt.md
#	01/README-pt.md
#	02/README-pt.md
#	03/README-pt.md
#	05/README-pt.md
#	06/README-pt.md
#	README-pt.md
pull/272/head
rnbastos 4 years ago
commit e90e260ab2

1
.gitignore vendored

@ -4,6 +4,7 @@ tmp.md
tmp*.png
book.tex
book.pdf
book.epub
log/*
/.idea
.idea/

@ -1,50 +1,48 @@
# Começando
## O que é um shader?
## O que é um fragment shader?
No capítlo anterior, nós descrevemos shaders como o equivalente da imprensa de Gutenberg para os gráficos. Por quê? E mais importante: o que é um shader?
No capítulo anterior descrevemos shaders como o equivalente dos avanços trazidos pela prensa de Gutenberg. Por que? E mais importante: o que é um shader?
![From Letter-by-Letter, Right: William Blades (1891). To Page-by-page, Left: Rolt-Wheeler (1920).](print.png)
![De letra-por-letra, Right: William Blades (1891). À página-por-página, Left: Rolt-Wheeler (1920).](print.png)
Se você já tem experiência em desenhar com computadores, já sabe que nesse processo você desenha um círculo, depois um retângulo, uma linha, alguns triângulos, até compor a imagem que você quer. Esse processo é muito similar a escrever uma carta ou livro à mão - é um conjunto de instruções em que se faz uma tarefa depois da outra.
Se você já tem experiência em desenhar em computadores, você sabe que nesse processo você desenha um círculo, depois um retângulo, uma linha, alguns triângulos até você finalmente compor a imagem desejada. O processo é muito similar a escrever uma carta ou livro à mão, um conjunto de instruções que executam uma tarefa atrás de outra.
Shaders também são um conjunto de instruções, mas as instruções são executadas todas de uma vez só para cada pixel na tela. Isso quer dizer que o código que você escreve tem que se comportar de modo diferente dependendo da posição do pixel na tela. Como um tipo na imprensa, seu programa vai funcionar como uma função que recebe uma posição e retorna uma cor, e quando é compilado, vai rodar extraordinariamente rápido.
Shaders são também um conjunto de instruções, mas as instruções são executadas todas ao mesmo tempo para cada pixel da tela. Isso significa que o código que você escreve têm que se comportar de maneira diferente, dependendo da posição do pixel na tela. Como uma prensa tipográfica, seu programa funcionará como uma função que recebe uma posição e retorna a respectiva cor, e, quando esse programa é compilado, ele será executado extraordinariamente rápido.
![Chinese movable type](typepress.jpg)
![Prensa tipográfica móvel chinesa](typepress.jpg)
## Por que os shaders são rápidos?
## Por que shaders são rápidos?
Para responder isso, eu lhe apresento as maravilhas do *processamento paralelo*.
Para responder essa pergunta, eu apresento as maravilhas do *processamento paralelo*.
Imagine a CPU do seu computador como uma grande esteira ou tubo industrial, e cada tarefa como algo que passa por ela - como uma linha de produção. Algumas tarefas são maiores que outras, o que significa que requerem mais tempo e energia para se lidar com elas. Dizemos assim que elas requerem mais poder de processamento. Por causa da arquitetura dos computadores, os trabalhos são forçados a serem executados em série; cada tarefa tem que ser terminada uma de cada vez. Computadores modernos geralmente têm grupos de quatro processadores que trabalham como essas linhas de produção, completando tarefas uma após a outra para manter as coisas rodando suavemente. Cada esteira é conhecida como *thread*.
Imagine a CPU do seu computador como um grande tubo (ou ducto) industrial, e cada tarefa como algo que passa por ele - como uma linha de produção. Algumas tarefas são maiores que outras, o que signica que elas requerem mais tempo e energia que as outras. Digamos que elas requerem mais poder de processamento. Por causa da arquitetura dos computadores, as tarefas são forçadas a serem executadas em série; cada tarefa é finalizada uma de cada vez. Computadores modernos geralmente tem grupos de quatro processadores para trabalhar com tais tubos, completando as tarefas sequencialmente e mantendo a linha de produção em movimento. Cada tubo é também conhecido como *thread*.
![CPU](00.jpeg)
Videogames e outras aplicações gráficas requerem muito mais poder de processamento que outros programas. Por causa de seu conteúdo gráfico, eles têm que fazer um número gigantesco de operações pixel-a-pixel. Cada pixel na tela precisa ser calculado, e em jogos 3D as geometrias e perspectivas precisam ser calculadas também.
Video games e outras aplicações gráficas requerem muito mais poder de processamento que outros programas. Por causa de seu conteúdo gráfico, eles precisam fazer um número enorme de operações pixel-por-pixel. Cada pixel da tela precisa ser computado, e em jogos em 3D geometrias e perspectivas também precisam ser calculadas.
Vamos voltar à nossa metáfora de tubos e tarefas. Cada pixel na tela representa uma pequena tarefa simples. Individualmente, cada tarefa de pixel não é uma grande questão para a CPU, mas (e esse é o problema) as pequenas tarefas têm que ser feitas em cada pixel na tela. Isso significa, em uma tela antiga em 800x600, que 480.000 pixels têm que ser processados por frame, o que significa 14.400.000 cálculos por segundo! Sim! Isso é um problema grande o suficiente para sobrecarregar um microprocessador. Em uma tela moderna retina 2880x1800, rodando a 60 frames por segundom esse cálculo daria até mais 311.040.000 cálculos por segundo. Como os engenheiros gráficos resolveram esse problema?
Vamos voltar para a nossa metáfora de tubos e tarefas. Cada pixel da tela representa uma tarefa pequena e simples. Individualmente, cada tarefa deste tipo não é um problema para o CPU, mas (e aqui mora o perigo) a pequena tarefa precisa ser repetida para cada pixel na tela! Isso significa que em uma tela antiga de 800x600, 480.000 pixels precisam ser processados pada cada frame, o que totaliza em 14.400.000 cálculos por segundo! Sim! Isso é um problema grande o suficiente para sobrecarregar um microprocessador. Em uma tela moderna com retina display medindo 2880x1800, executando a 60 frames por segundo, esse cálculo resulta em até 311.040.000 cálculos por segundo. Como engenheiros gráficos resolvem esse problema?
![](03.jpeg)
É aí que o processamento paralelo se torna uma boa solução. Ao invés de ter uma dupla de microprocessadores grandes e poderosos, ou *tubos*, é mais inteligente ter um monte de pequenos microprocessadores rodando em paralelo ao mesmo tempo. É isso que é uma GPU - Unidade de Processamento Gráfico.
Neste caso, processamento em paralelo se torna uma boa solução. Em vez de ter alguns microprocessadores grandes e poderosos, ou *tubos*, é mais inteligente ter um monte de minúsculos microprocessadores rodando em paralelo ao mesmo tempo. Isso é o que a Unidade de Processamento Gráfico (Graphic Processor Unit ou GPU) é.
![GPU](04.jpeg)
Imagine os minúsculos processadores como uma mesa de tubos, e os dados de cada pixel como sendo uma bola de ping-pong. 14.400.000 bolas de ping-pong por segundo podem obstruir quase qualquer tubo. Mas uma mesa de 800x600 pequenos tubos recebendo 30 ondas de 480.000 pixels por segundo pode ser manuseado suavemente. Isso funciona do mesmo jeito para resoluções mais altas - quanto mais hardware paralelo você tem, maior o stream que ele pode gerenciar.
Imagine os minúsculos microprocessadores como uma mesa de tubos, e os dados de cada pixel como uma bola de ping-pong. 14.400.000 bolas de ping-pong por segundo podem obstruir quase qualquer tubo. Mas a mesa com 800x600 pequenos tubos recebendo 30 ondas de 480.000 pixels por segundo pode manejar esse fluxo tranquilamente. Funciona do mesmo jeito em resoluções maiores - quanto mais hardware em paralelo você tem, maior o fluxo que eles podem manejar.
Um outro "super poder" da GPU são funções especiais matemáticas aceleradas via hardware, de modo que operações matemáticas complicadas são resolvidas diretamente pelos microchips ao invés de serem por software. Isso significa operações trigonométricas e de matrix extra rápidas - tanto quanto a eletricidade pode ir.
Outro "super poder" da GPU são funções matemáticas especiais aceleradas via hardware, logo operações matemáticas mais complicadas são resolvidas diretamente pelos microchips em vez do software. Isso resulta em operações trigonométricas e matriciais extra rápidas - tão rápidas quanto a eletricidade.
## O que é GLSL?
GLSL é a sigla de openGL Shading Language, o que é o padrão específico de shader que você verá nos próximos capítulos. Existem outros tipos de shaders, dependendo do hardware ou sistemas operacionais. Aqui trabalharemos com as specificações do openGL, reguladas por [Khronos Group](https://www.khronos.org/opengl/). Entender a história do OpenGL pode ser útil se compreender a maior parte das estranhas convenções, para isso eu te recomendo a dar uma olhada em: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html)
GLSL significa "openGL Shading Language", que é o padrão específico dos programas shader que você vai ver nos próximos capítulos. Existem outros tipos de shaders, dependendo do hardware and Sistema Operacional. Aqui vamos trabalhar com as especificações openGL reguladas pelo [Khronos Group](https://www.khronos.org/opengl/). Entender a história do OpenGL pode ser de muita ajuda para entender a maioria das convenções estranhas que ele tem, e para isso eu recomendo dar uma olhada em: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html)
## Por que shaders têm uma má reputação?
## Por que os shaders são tão dolorosos?
Como disse o Tio Ben “com grandes poderes vêm grandes responsabilidades” e computação em paralelo segue essa regra; o poderoso design aquitetônico da GPU vem com suas próprias limitações e restrições.
Como o Tio Ben disse, “com grandes poderes vêm grandes responsabilidades,” e computação paralela segue essa regra; o design arquitetural poderoso da GPU vem com suas restrições e dificuldades.
Para cada tubo - ou thread - ser executado em paralelo, eles têm que ser independentes de outras threads. Podemos dizer que threads são *cegas* com relação ao que as outras threads estão fazendo. Essa restrição faz com que todos os dados devem fluir na mesma direção. Deste modo é impossível checar o resultado de outra thread, modificar o input de dados ou passar o resultado de uma thread para outra. Permitir comunicação entre as threads coloca a integridade dos dados em risco.
Para rodar em paralelo, cada tubo, ou thread, precisa ser independente dos demais. Digamos que as threads são *cegas* para o que o resto das threads está fazendo. Esta restrição implica em que todo o dado deve fluir na mesma direção. Então, é impossível checar o resultado de outra thread, modificar os dados de entrada, ou passar a saída de uma thread para outra. Permitir comunicação entre threads coloca a integridade dos dados em risco.
Além disso, a GPU mantém os microprocessadores (os tubos) constantemente ocupados; assim que eles ficam livres eles recebem novas informações para serem processadas. É impossível para uma thread saber o que ela estava fazendo num momento anterior. Isso poderia ser desenhar um botão para a UI do sistema operacional, depois renderizar uma porção do céu em um jogo, seguido de mostrar o texto de um email. Cada thread não é só **cega** como **sem memória**. Apesar da abstração requerida para programar uma função genérica que muda o resultado pixel por pixel dependendo da posição do mesmo, as limitações desta cegueira e falta de memória faz com que os shaders não sejam muito populares entre programadores iniciantes.
Além disso, a GPU mantém o microprocessador (os tubos) constantemente ocupado; assim que ficam livres, já recebem nova informação para processar. É impossível para uma thread saber o que ela estava fazendo no momento anterior. Ela poderia estar desenhando um botão da UI do Sistema Operacional, então renderizar uma parte do céu num jogo, e depois mostrar o texto de um email. Cada thread não é apenas **cega** mas também **sem memória**. Além da abstração requerida para codificar uma função geral que muda o resultado pixel a pixel dependendo de sua posição, as restrições de cegueira e falta de memória tornam os shaders pouco populares entre os programadores principiantes.
Não se preocupe! Nos capítulos seguintes, vamos aprender passo a passo como sair de um nível simples ao avançado nas computações de shaders. Se você está lendo isso com um browser moderno, vai poder brincar com exemplos interativos. Então, não vamos mais demorar com a diversão, e aperte *Próximo >>* para pular para o código!
Não se preocupe! Nos capítulos seguintes aprenderemos passo-a-passo a trabalhar com shaders com exemplos que vão de simples a avançados. Se você está lendo este livro em um navegador moderno, você pode poderá brincar com os exemplos interativos. Então clique em *Next >>* e mãos à obra!

@ -1,42 +1,42 @@
## Hello World
## Olá mundo
Geralmente, o exemplo do "Hello world!" é o primeiro passo para aprender uma nova linguagem. É um programa simples de uma linha, que exibe uma mensagem alegre de boas-vindas.
Geralmente o exemplo "Olá mundo" é o primeiro passo ao aprender uma nova linguagem. É um programa de uma linha de código que retorna uma entusiástica mensagem de boas vindas e declara as oportunidades que nos aguarda.
No mundo da GPU, renderizar texto é uma tarefa complicada demais para um primeiro passo, então, ao invés, vamos escolher uma cor brilhante para mostrar nosso entusiasmo!
No mundo da GPU, renderizar texto é uma tarefa muito complicada para ser o primeiro passo, portanto usaremos uma cor brilhante cor de boas-vindas para representar nosso entusiasmo!
<div class="codeAndCanvas" data="hello_world.frag"></div>
Se você está lendo este livro num browser, o bloco de código antetior é interativo. Isso significa que você pode clicar e mudar qualquer pedaço do código que quiser explorar. Mudanças serão atualizadas imediatamente graças à arquitetura da GPU, que compila e substitui os shaders *on the fly*. Faça uma tentativa, mude os valores da linha 6.
Se você está lendo este livro em um navegador, o bloco de código acima é interativo. Isso significa que você pode clicar e modificar qualquer parte do código em que você quiser explorar sua funcionalidade. As mudanças serão atualizadas imediatamente graças à arquitetura da GPU que compila e substitui os shaders *instantaneamente*. Experimente modificar os valores da linha 8.
Embora essas simples linhas de código não se pareçam muito, podemos inferir um conhecimento substancial delas:
Embora essas simples linhas de código não parecem ser tão interessantes, podemos inferir muita coisa sobre elas:
1. Shader Language tem uma única função `main` que retorna uma cor no fim. Isso é similar ao C.
1. Linguagem de shader Shader Language possui uma função principal - `main` - que retorna uma cor. Isto é similar a C.
2. A cor final do pixel é associada à variável global reservada `gl_FragColor`.
2. A cor final do pixel é atribuída pela variável global reservada `gl_FragColor`.
3. Essa linguagem, do estilo do C, tem *variáveis* internas já construídas (como `gl_FragColor`), *funções* and *tipos*. Neste caso, acabamos ser apresentados ao `vec4` que é um vetor de quatro dimensões de precisão de ponto flutuante. Mais tarde vamos ver mais tipos como `vec3` e `vec2` juntos com os populares:`float`, `int` e `bool`.
3. Essa linguagem similar a C tem *variáveis* nativas (como `gl_FragColor`), *funções* e *tipos*. Nesse caso fomos vemos `vec4`, que representa um vetor em quatro dimensões com precisão de ponto flutuante. Mais adiante veremos outros tipos como `vec3` e `vec2` além dos populares: `float`, `int` and `bool`.
4. Se olharmos de perto o tipo `vec4` podemos inferir que os quatro argumentos correpondem aos canais RED (vermelho), GREEN (verde), BLUE (azul) e ALPHA. Podemos também ver que esses valores são *normalizados*, o que significa que eles vão de `0.0` a `1.0`. Depois vamos aprender como a normalização faz com que fique mais fácil *mapear* valores entre variáveis.
4. Se observarmos o tipo `vec4` podemos inferir que os quatro argumentos correspondem aos canais RED (vermelho), GREEN (verde), BLUE (azul) e ALPHA (alfa). Também vemos que esses valores são *normalizados*, ou seja, eles vão de `0.0` a `1.0`. Mais tarde aprenderemos como normalizar valores facilitam o seu *mapeamento* entre variáveis.
5. Outra *característica do C* importante que podemos ver nesse exemplo é a presença de macros de preprocessador. Macros são parte de um passo da pré-compilação. Com elas, é possível definir (`#define`) variáveis globais e fazer algumas operações condicionais básicas (com `#ifdef` e `#endif`). Todos os comandos de macro começam com hashtag (`#`). A pré-compilação acontece logo antes de compilar e copia todas as chamadas a `#defines` e checa as condicionais `#ifdef` (é definido) e `#ifndef` (não é definido). No nosso "hello world!", só inserimos a linha 2 se `GL_ES` estiver definida, o que geralmente acontece quando o código é compilado em dispositivos móveis e browsers.
5. Outra importante *característica de C* que podemos ver neste exemplo é a presença de macros de preprocessador. Macros são parte do passo de pré-compilação. Com eles podemos definir variáveis globais (com `#define`) e fazer operações condicionais básicas (com `#ifdef` e `#endif`). Todos os comandos de macros começam com uma hashtag (`#`). A pré-compilação acontece logo antes da compilação e copia todas as chamadas para condicionais `#define` e checa` #ifdef` (está definido) e` #ifndef` (não está definido). Em nosso exemplo "Olá mundo" acima nós inserimos na linha 2 se `GL_ES` for definido, o que provavelmente acontece quando o código é compilado em celulares e navegadores.
6. Tipos float são vitais em shaders, então o nível de *precisão* é crucial. Precisão mais baixa significa renderização mais rápida, ao custo da qualidade. Você pode ser detalhista e especificar a precisão de cada variável que usa ponto flutuante. Na primeira linha (`precision mediump float;`) estamos setando todos os floats para precisão média. Mas podemos escolher setar para baixa precisão (`precision lowp float;`) ou alta (`precision highp float;`).
6. Tipos float são vitais em shaders, então o nível de *precisão* é crucial. Menor precisão maior a velocidade de renderização, porém a qualidade é afetada. Você pode ser meticuloso e especificar a precisão para cada variável que usa ponto flutuante. Na primeira linha (`precision mediump float;`) estamos ajustando todos os floats para precisão média. Mas podemos ajustá-las para baixa (`precision lowp float;`) ou alta (`precision highp float;`) também.
7. Por fim, e talvez mais importantem o detalhe é que specs GLSL não garantem que as variáveis serão convertidas automaticamente. O que isso quer dizer? Os fabricantes têm diferentes abordagens para acelerar os gráficos que o cartão processa mas eles são forçados a garantir specs mínimas. Conversão automática não é uma delas. Em nosso exemplo “hello world!” o `vec4` tem precisão de ponto flutuante e para isso, ele espera que seja associado com valores `floats`. Se você quiser fazer um código bom e consistente e não gastar horas debugando telas em branco, acostume-se a colocar o ponto (`.`) em seus floats. Esse tipo de código não vai funcionar sempre:
7. O final, e talvez mais importante detalhe é que a especificação da GLSL não garante que as variáveis serão automaticamente convertidas. O que isso significa? Fabricantes têm soluções para acelerar a os processos da placa gráfica mas eles são forçados a garantir as especificações mínimas. Conversão automática não está entre delas. Em nosso exemplo "olá mundo!" `vec4` tem precisão de ponto flutuante e por isso ele espera ser convertido com `floats`. Se você quiser escrever código de maneira consistente e não gastar horas not spend hours investigando telas em branco, se acostume a colocar um ponto (`.`) em seus flutuantes (floats). Esse tipo de código às vezes não funcionará:
```glsl
void main() {
gl_FragColor = vec4(1,0,0,1); // ERRO
gl_FragColor = vec4(1,0,0,1); // ERROR
}
```
Agora que descrevemos os elementos mais relevantes do nosso programa "hello world!", é hora de clicar no blodo de código e começar a desafiar com tudo o que aprendemos. Você vai notar que em caso de erros, o programa vai falhar a compilação, mostrando uma tela em branco. Existem algumas coisas legais que você pode tentar, por exemplo:
Agora que descrevemos os elementos mais relevantes em nosso programa "Olá mundo!", chegou a hora de clicar no bloco de código e começar a aplicar o que aprendemos até agora. Você notará que, quando houver um erro, o programa não compilará e renderizará uma tela em branco. Têm algumas coisas interessantes que você pode tentar, por exemplo:
* Tente substituir os floats com inteiros, sua placa gráfica pode ou não tolerar esse comportamento.
* Tente substituir flutuantes (floats) por números inteiros (integers), pode ser que a sua placa gráfica não ofeça suporte.
* tente descomentar a linha 6 e não definir um valor de pixel na função.
* Tente comentar a linha 8 e não atribuir nenhum valor nessa função.
* Tente fazer uma função separada que retorne uma cor específica e use a função dentro do `main()`. Como dica, aqui está o código para uma função que retorna a cor vermelha:
* Tente escrever outra função à parte que retorna uma cor específica e a utilize em `main()`. Dica: aqui está o código para uma função que retorna a cor vermelho:
```glsl
vec4 red(){
@ -44,10 +44,10 @@ vec4 red(){
}
```
* Há vários modos de contruit tipos `vec4`, tente descobrir outras formas. O seguinte é uma delas:
* Existem múltiplas maneiras diferentes para construir tipos `vec4`, tente descobrir outras maneiras. Este é um deles:
```glsl
vec4 color = vec4(vec3(1.0,0.0,1.0),1.0);
```
Embora esse exemplo não seja muito excitante, é o exemplo mais básico - estamos mudando todos os pixels dentro do canvas para exatamente a mesma cor. No próximo capítulo, vamos ver como mudar a cor do pixel usando dois tipos de entrada: espaço (o lugar do pixel na tela) e tempo (o número de segundos desde que a página foi carregada).
Apesar deste exemplo não ser tão empolgante, ele é o exemplo mais básico - estamos modificando todos os pixels da tela ao mesmo tempo e atribuindo a eles a mesma cor. No próximo capítulo veremos como mudar as cores dos pixels usando dois tipos de entrada (input): espaço (a posição do pixel na tela) e tempo (o número de segundos desde que a página foi carregada).

@ -6,7 +6,7 @@ In GPU-land rendering text is an overcomplicated task for a first step, instead
<div class="codeAndCanvas" data="hello_world.frag"></div>
If you are reading this book in a browser the previous block of code is interactive. That means you can click and change any part of the code you want to explore. Changes will be updated immediately thanks to the GPU architecture that compiles and replaces shaders *on the fly*. Give it a try by changing the values on line 6.
If you are reading this book in a browser the previous block of code is interactive. That means you can click and change any part of the code you want to explore. Changes will be updated immediately thanks to the GPU architecture that compiles and replaces shaders *on the fly*. Give it a try by changing the values on line 8.
Although these simple lines of code don't look like a lot, we can infer substantial knowledge from them:
@ -34,7 +34,7 @@ Now that we've described the most relevant elements of our "hello world!" progra
* Try replacing the floats with integers, your graphic card may or may not tolerate this behavior.
* Try commenting out line 6 and not assigning any pixel value to the function.
* Try commenting out line 8 and not assigning any pixel value to the function.
* Try making a separate function that returns a specific color and use it inside `main()`. As a hint, here is the code for a function that returns a red color:

@ -2,6 +2,8 @@
precision mediump float;
#endif
uniform float u_time;
void main() {
gl_FragColor = vec4(1.0,0.0,1.0,1.0);
}

@ -1,61 +1,61 @@
## Uniformes
## Uniforms
Até agora, nós vimos como a GPU gerencia um grande número de threads, cada uma responsável por associar a cor a uma fração da imagem. Embora cada thread paralela seja cega às outras, precisamos conseguir enviar entradas da CPU para todas as threads. Por causa da arquitetura das placas gráficas, essas entradas vão ser iguais (*uniform*) para todas as threads e necessariamente setadas como *read only*. Em outras palavrasm cada thread recebe os mesmos dados que pode ler, mas não pode mudar.
Até agora, vimos como a GPU lida um grande número de threads em paralelo, cada uma sendo responsável por atribuir a cor a uma porção da imagem.Apesar de cada thread paralela não saber da existência das outras, precisamos ser capazes de enviá-las algumas entradas (inputs) da CPU. Devido à arquitetura das placas de vídeo, essas entradas serão iguais (*uniform*) para todas as threads e necessariamente determinadas como *somente leitura*. Em outras palavras, cada thread recebe os mesmos dados, os quais se podem ler mas não podem se alterar.
Essas entradas são chamadas de `uniform` em vêm na maioria dos tipos suportados: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` e `samplerCube`. Uniformes são definidos com o tipo correspondente no topo do shader, logo depois de associar a precisão default.
Essas entradas são chamamadas de `uniform` e podem ser de tipos diferentes, como: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` e `samplerCube`. Uniformes são definidas com o tipo correspondente no começo do código, logo após atribuir a precisão padrão de pontos flutuantes,
```glsl
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution; // Tamanho do Canvas (width,height)
uniform vec2 u_mouse; // posição do mouse em pixels da tela
uniform float u_time; // Tempo em segundos desde carregado
uniform vec2 u_resolution; // Canvas size (width,height)
uniform vec2 u_mouse; // mouse position in screen pixels
uniform float u_time; // Time in seconds since load
```
Você pode imaginar nos uniforms como sendo pequenas pontes entre a CPU e a GPU. Os nomes vão variar de uma implementação para outra, mas nessa série de exemplos eu sempre vou passar `u_time` (tempo em seguntos desde que shader começou), `u_resolution` (tamanho do 'letreiro' onde o shader está sendo desenhado) e `u_mouse` (posição do mouse dentro do letreiro, em pixels). Vou seguir convenção de colocar `u_` antes do nome do uniform para ser explícito sobre a natureza dessa variável, mas você vai encontrar todos os tipos de nomes para os uniformes. Por exemplo [ShaderToy.com](https://www.shadertoy.com/) usa os mesmos uniformes, mas com os seguintes nomes:
Imagine os uniforms como pequenas pontes entre a CPU e a GPU. Os nomes variam dependendo da implementação, mas nessa série de exemplos estarei sempre usando: `u_time` (tempo em segundos desde que o shader foi iniciado), `u_resolution` (tamanho da tela onde o shader está sendo desenhado) and `u_mouse` (posição em pixels do mouse dentro da tela). Estarei seguindo a convenção ao colocar `u_` antes do nome da uniform para evidenciar a natureza desta variável mas você encontrará outros tipos de nomenclatura para uniforms. Por exemplo [ShaderToy.com](https://www.shadertoy.com/) utiliza os mesmos uniforms mas com os seguintes nomes:
```glsl
uniform vec3 iResolution; // resolução da viewport (em pixels)
uniform vec4 iMouse; // coordenadas dos pixels do mouse . xy: atual, zw: clique
uniform float iTime; // tempo de execução do shader (em segundos)
uniform vec3 iResolution; // viewport resolution (in pixels)
uniform vec4 iMouse; // mouse pixel coords. xy: current, zw: click
uniform float iTime; // shader playback time (in seconds)
```
Chega de papo, vamos ver os uniforms em ação. No código a seguir, usamos `u_time` - o número de segundos desde que o shader começou a executar - junto com uma função seno para animar a transição da quantidade de vermelho no letreiro.
Chega de conversa, vamos ver os uniforms em ação. No código abaixo, usamos `u_time` - o número de segundos desde que o shader começou a ser executado - junto com uma função de seno para animar a transição da quantidade de vermelho na tela.
<div class="codeAndCanvas" data="time.frag"></div>
Como você pode ver, GLSL tem mais surpresas. A GPU tem funções de ângulo, trigonométricas e exponenciais, aceleradas por hardware. Algumas dessas funções são: [`sin()`](../glossary/?search=sin), [`cos()`](../glossary/?search=cos), [`tan()`](../glossary/?search=tan), [`asin()`](../glossary/?search=asin), [`acos()`](../glossary/?search=acos), [`atan()`](../glossary/?search=atan), [`pow()`](../glossary/?search=pow), [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log), [`sqrt()`](../glossary/?search=sqrt), [`abs()`](../glossary/?search=abs), [`sign()`](../glossary/?search=sign), [`floor()`](../glossary/?search=floor), [`ceil()`](../glossary/?search=ceil), [`fract()`](../glossary/?search=fract), [`mod()`](../glossary/?search=mod), [`min()`](../glossary/?search=min), [`max()`](../glossary/?search=max) and [`clamp()`](../glossary/?search=clamp).
Como você pode ver, GLSL tem mais surpresas. A GPU tem funções angulares, trigonométricas e exponenciais aceleradas pelo hardware. Algumas dessas funções são: [`sin()`](../glossary/?search=sin), [`cos()`](../glossary/?search=cos), [`tan()`](../glossary/?search=tan), [`asin()`](../glossary/?search=asin), [`acos()`](../glossary/?search=acos), [`atan()`](../glossary/?search=atan), [`pow()`](../glossary/?search=pow), [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log), [`sqrt()`](../glossary/?search=sqrt), [`abs()`](../glossary/?search=abs), [`sign()`](../glossary/?search=sign), [`floor()`](../glossary/?search=floor), [`ceil()`](../glossary/?search=ceil), [`fract()`](../glossary/?search=fract), [`mod()`](../glossary/?search=mod), [`min()`](../glossary/?search=min), [`max()`](../glossary/?search=max) e [`clamp()`](../glossary/?search=clamp).
Agora é a hora de brincar de novo com o código acima.
Agora é novamente a hora de experimentar com o código acima.
* Diminua a frequência até que a mudança de cor seja quase imperceptível.
* Diminua a frequência até a mudança de cor se tornar quase imperceptível.
* Acelere até você ver cada cor sem efeito de flicker.
* Aumente a velocidade até que seja possível ver somente uma cor sem oscilações.
* Brinque com os três canais (RGB) em frequências diferentes para conseguir padrões e comportamentos interessantes.
* Experimente alterar os valores dos três canais de cores (RGB) em diferentes frequências a fim de obter padrões e comportamentos interessantes.
## gl_FragCoord
Da mesma forma que a GLSL nos dá um output default, `vec4 gl_FragColor`, ela também nos dá um input default, `vec4 gl_FragCoord`, que contém aos coordenadas na tela do *pixel* ou *fragmento da tela* que a thread ativa está trabalhando. Com `vec4 gl_FragCoord`, sabemos onde uma thread está trabalhando dentro do letreiro. Neste caso, não chamamos de `uniform` porque ela será diferente de uma thread para a outra, então a `gl_FragCoord` é chamada de *variante*.
Da mesma maneira que GLSL nos dá um output padrão, `vec4 gl_FragColor`, ele também nos dá um input padrão, `vec4 gl_FragCoord`, que possui as coordenadas de um *pixel* ou *screen fragment* com que a thread ativa está processando. Com `vec4 gl_FragCoord` podemos saber onde a thread está trabalhando dentro da tela. Neste caso, não chamaremos isso de `uniform` porque seu valor será diferente para cada thread, logo `gl_FragCoord` é chamada de *varying*.
<div class="codeAndCanvas" data="space.frag"></div>
No código acima, nós *normalizamos* a coordenada do fragmento dividindo-a pela resolução total do letreiro. Fazendo isso, os valores ficarão entre `0.0` e `1.0`, o que torna mais fácil mapear os valores X e Y para os canais RED e GREEN.
No código acima nós *normalizamos* as coordenadas do fragmento ao dividi-las pela resolução total da tela. Fazendo isso, os valores serão entre `0.0` e `1.0`, o que facilita mapear os valores de X e Y para os canais RED e GREEN.
Na "shaderlândia", não temos muitos recursos para depurar, além de associar cores fortes a variáveis e tentar fazer um sentido com elas. Você vai descobrir que, às vezes, codificar em GLSL é muito parecido com colocar navios dentro de garrafas. É igualmente difícil, bonito e gratificante.
No mundo dos shaders, não temos muitos recursos para depurar bugs além de atribuir uma cor marcante às variáveis e tentar entender o que está acontecendo com as mesmas. Você descobrirá que, às vezes, programar em GLSL é bem similar a construir navios dentro de garrafas. É igualmente difícil, bonito e gratificante.
![](08.png)
Agora é a hora de tentar e desafiar nosso entendimento desse código.
Agora é a hora de tentar e desafiar a nossa compreensão desse código.
* Você pode dizer onde fica a coordenada `(0.0, 0.0)` em nosso canvas?
* Você pode dizer onde a coordenada `(0.0, 0.0)` está em nossa tela?
* E as coordenadas `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` e `(1.0, 1.0)`?
* E quanto `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` e `(1.0, 1.0)`?
* Você consegue imaginar como usar `u_mouse` sabendo que os valores são em pixels e NÃO valores normalizados? Você pode usar isso para mover as cores ao redor?
* Você pode adivinhar como se usa o uniform `u_mouse`, sabendo que os valores são em pixel e NÃO em valores normalizados? Você pode usá-lo para mover as cores ao longo da tela?
* Você pode imaginar uma forma interessante de mudar esse padrão de cores usando as coordenadas `u_time` e `u_mouse`?
* Você consegue imaginar uma maneira interessante para mudar esse padrão de cor usando `u_time` e as coordenadas de `u_mouse`?
Depois de fazer esses exercícios, você poderia pensar em que mais poderia tentar seus novos poderes de shader. No capítulo seguinte, vamos ver como fazer sua própria ferramenta de shader em three.js, Processing, e openFrameworks.
Após completar estes exercícios, você talvez se pergunte onde mais você pode aplicar seu novo superpoder de shader. No próximo capítulo veremos como fazer as nossas próprias ferramentas de shader em three.js, Processing, e openFrameworks.

@ -1,43 +1,43 @@
# Desenho algorítmico
## Funções de formas
# Algoritmos de desenho
## Modelagem de funções
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á.
Este capítulo poderia se chamar "Lição de pintar a cerca com o Sr. Miyagi". Anteriormente, nós mapeamos as posições normalizadas de *x* e *y* para os canais *red* e *green*. Essencialmente, nós criamos uma função que recebe um vetor bidimensional (x e y) e retornamos um com quatro dimensões (vermelho, verde, azul e alpha). Mas antes de irmos além de transformações dos dados entre as dimensões, precisamos fazer algo mais simples... muito mais simples: entender como criar uma função unidimensional. Quanto mais energia e tempo que você gastar dominando isso, mais forte seu karatê de 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.
A estrutura do código a seguir será nossa cerca. Nela, nós visualizaremos os valores normalizados da coordenada *x* (`st.x`) de dois jeitos: uma com a claridade (observe o belo gradiente de branco para preto) e a outra é traçando uma linha verde por cima (neste caso, o valor de *x* será atribuído diretamente a *y*). Não foque tanto na função de traçar, nós a veremos com mais detalhes em alguns minutos.
<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.
**Nota rápida**: O construtor do tipo `vec3` "entende" que você quer atribuir o mesmo valor aos três canais de cores, enquanto `vec4` entende que você quer construir um vetor quadridimensional usando um vetor tridimensional *um* somado a um quarto valor (neste caso, o valor que controlará o alpha ou opacidade). Veja as linhas 20 e 26 acima por exemplo.
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.
Este código é a sua cerca: É importante observar e entendê-lo. Você voltará algumas vezes para este espaço entre *0.0* e *1.0*. Aprenderá a arte de mesclar e dar forma a esta 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*.
Essa relação de um pra um entre *x* e *y* (ou de brilho) é conhecida como *interpolação linear*. A partir daqui, nós usaremos algumas funções matemáticas para dar *forma* a linha. Por exemplo, nós podemos elevar *x* à quinta potência para criar uma linha *curvada*.
<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.
Interessante, não é? Na linha 22, tente diferentes expoentes: 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 será de grande ajuda. Usar esses tipos de funções matemáticas aqui e ali nos dará um controle significativo do nosso código, uma espécie de acumpultura de dados que permite que você controle a fluência dos 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.
[`pow()`](../glossary/?search=pow) é uma função nativa no GLSL e existem muitas outras. A maioria delas são aceleradas em nível de hardware, o que significa que se elas forem usadas da forma certa e com juízo, farão 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`.
Substitua 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 destas funções são mais interessantes quando você experimenta utilizando PI. Você pode ver na linha 8 que eu defini uma macro que retornará qualquer chamada de `PI` com o valor de `3.14159265359`.
### Step e Smoothstep
### Step e smoothstep
GLSL também tem algumas funções únicas nativas de interpolação, aceleradas por hardware.
GLSL também tem algumas exclusivas funções nativas de interpolação que são aceleradas pelo 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`.
A interpolação [`step()`](../glossary/?search=step) recebe dois parâmetros. O primeiro é para o limite ou limiar, enquanto o segundo é o valor que nós queremos passar. Qualquer valor acima do limite retornará `0.0` e qualquer um acima do limite retornará `1.0`.
Tente mudar esse valor de limite na linha 20 do código acima.
Experimente mudar este valor de limiar na linha 20 do código a seguir.
<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.
A outra função exclusiva é conhecida como [`smoothstep()`](../glossary/?search=smoothstep). Dado um intervalo de dois números, está função irá interpolar os valores entre o intervalo definido. Os dois primeiros parâmetros são para o início e o final da transição, enquanto o terceiro é o valor que será interpolado.
<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?
No exemplo anterior, na linha 12, veja que estamos usando smoothstep para desenhar a linha verde na função `plot()`. Pra cada posição dentro do eixo *x*, esta função faz uma *marcação* num valor específico de *y*. Como? Conectando duas [`smoothstep()`](../glossary/?search=smoothstep) juntas. Dê uma olhada na seguinte função, troque a linha 20 acima por esta, e imagine-a como um corte vertical. O fundo se parece com uma linha, certo?
```glsl
float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x);
@ -45,96 +45,96 @@ 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.
Quando queremos usar um pouco de matemática para animar, dar forma e mesclar 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.
Essas duas funções trigonométricas básicas trabalham juntas para construir circunferências que são tão úteis como o canivete suíço de MacGyver. É importante entender como elas se comportam e de quais formas elas podem ser combinadas. Em poucas palavras, dado um ângulo (em radianos), elas retornarão a posição correta de *x* ([cosseno](../glossary/?search=cos)) e *y* ([seno](../glossary/?search=sin)) de um ponto na linha de uma circunferência de raio igual a 1. O fato de elas retornarem valores normalizados (que vão de 1 a -1) de maneira suave faz delas, ferramentas incríveis.
![](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.
Enquanto é difícil descrever todas as relações entre as funções trigonométricas e circunferências, a animação acima faz um ótimo trabalho em exemplificar visualmente esta relação.
<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.
Preste muita atenção nesta onda de seno. Note como o valor de *y* flui suavemente entre +1 e -1. Como vimos nos exemplos de tempo no capítulo anterior, podemos usar esse movimento rítmico do [`sin()`](../glossary/?search=sin) para animar propriedades. Se você estiver lendo este exemplo em um navegador, você verá que você pode alterar o código da fórmula acima para observar como as ondas mudam. (Nota: não se esqueça do ponto e vírgula no final das linhas).
Tente os exercícios seguintes veja o que acontece:
Experimente com os seguintes exercícios e veja o que acontece:
* Adicione o tempo (`u_time`) ao *x* antes de calcular o `seno`. Internalize o **movimento** ao longo de *x*.
* Some o tempo (`u_time`) ao *x* antes de calcular o `sin`. Perceba 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 *x* por `PI` antes de calcular o `sin`. Veja como a **frequência** entre as fases se torna mais comprimida.
* 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.
* Multiplique *x* pelo tempo (`u_time`) antes de calcular o `sin`. Note que u_time já pode ter se tornado um valor muito grande, o que torna difícil enxergar a linha verde.
* 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.
* Some 1.0 a [`sin(x)`](../glossary/?search=sin). Veja como toda a onda foi **deslocada** para cima e agora seus valores vão de 0.0 a 2.0.
* Multiplique [`sin(x)`](../glossary/?search=sin) por 2.0. Note como a **amplitude** dobra de tamanho.
* Multiplique [`sin(x)`](../glossary/?search=sin) por 2.0. Veja como a **amplitude** dobra seu tamanho.
* Compute o valor absoluto ([`abs()`](../glossary/?search=abs)) de `sin(x)`. Parece com o rastro de uma bola **saltitante**.
* Calcule o valor absoluto ([`abs()`](../glossary/?search=abs)) do `sin(x)`. Se parece com o rastro de uma *bola quicando*.
* Extraia apenas a parte fracionária ([`fract()`](../glossary/?search=fract)) do resultado de [`sin(x)`](../glossary/?search=sin).
* Extraia apenas a parte fracionária ([`fract()`](../glossary/?search=fract)) do resultante do [`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.
* Some o número inteiro mais alto ([`ceil()`](../glossary/?search=ceil)) e o inteiro mais baixo ([`floor()`](../glossary/?search=floor)) do resultante do [`sin(x)`](../glossary/?search=sin) para conseguir uma onda digital de 1 e -1.
### Algumas funções extras úteis
### Outras funções ú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!
No final do último exercício nós apresentamos algumas novas funções. Agora é hora de experimentar cada uma descomentando as linhas abaixo, uma de cada vez. É importante entender o funcionamento e comportamento destas funções. Eu sei, você deve estar se perguntando... Por quê? Uma rápida pesquisa no google de "arte generativa" (ou generative art) te mostrará. Lembre-se que estas funções são a nossa cerca. Nós estamos dominando o movimento em uma dimensão, para cima e para baixo. Logo, usaremos duas, três 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>
<div class="simpleFunction" data="y = mod(x,0.5); // return x modulo of 0.5
//y = fract(x); // return only the fraction part of a number
//y = ceil(x); // nearest integer that is greater than or equal to x
//y = floor(x); // nearest integer less than or equal to x
//y = sign(x); // extract the sign of x
//y = abs(x); // return the absolute value of x
//y = clamp(x,0.0,1.0); // constrain x to lie between 0.0 and 1.0
//y = min(0.0,x); // return the lesser of x and 0.0
//y = max(0.0,x); // return the greater of x and 0.0 "></div>
### Funções de forma avançadas
### Modelando funções 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.
[Golan Levin](http://www.flong.com/) tem uma ótima documentação de modelagem de funções complexas que são de extraordinária ajuda. Portá-las para GLSL é uma excelente forma para começar seu próprio banco de trechos de códigos.
* Funções de Forma - Polinomiais: [www.flong.com/texts/code/shapers_poly](http://www.flong.com/texts/code/shapers_poly/)
* [Polynomial Shaping Functions: 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/)
* [Exponential Shaping Functions: 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/)
* [Circular & Elliptical Shaping Functions: 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/)
* [Bezier and Other Parametric Shaping Functions: 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.
Como chefs que coletam temperos e ingredientes exóticos, artistas digitais e programadores criativos tem um amor único por trabalhar nas suas próprias funções.
[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()`:
[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), dê uma olhada na seguinte na seguinte tradução destas funções para GLSL. Preste atenção nas pequenas mudanças necessárias, como colocar o "." (ponto) nos números de ponto flutuantes ou usar o nome em GLSL para as *Funções em C*; por exemplo, em vez de `powf()`, usamos `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.
Para mantermos sua motivação lá em cima, aqui temos um exemplo elegante (feito por [Danguafer](https://www.shadertoy.com/user/Danguafer)) em masterizar o karatê das funções.
<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.
No *Próximo >>* capítulo, nós começaremos a usar nossos novos movimentos. Primeiro misturando cores e em seguida, 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ê.
Dê uma olhada na seguinte tabela de equações feita por [Kynd](http://www.kynd.info/log/). Veja como ele está combinando as funções e suas propriedades para controlar os valores entre 0.0 e 1.0. Agora é a hora de você praticar replicando estas funções. Lembre-se que quanto mais você praticar, melhor será o seu karatê de shaders.
![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.
Aqui temos algumas ferramentas que facilitarão a visualização destes 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.
* Grapher: Se você estiver em um MacOS, digite `grapher` no sua Busca Spotlight e você poderá usar essa ferramenta super conveniente.
![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.
* [GraphToy](http://www.iquilezles.org/apps/graphtoy/): mais uma vez [Iñigo Quilez](http://www.iquilezles.org) fez uma ferramenta para visualizar funções em 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.
* [Shadershop](http://tobyschachman.com/Shadershop/): esta surpreendente ferramenta criada por [Toby Schachman](http://tobyschachman.com/) lhe ensinará como construir funções complexas em uma forma inacreditavelmente visual e intuitiva.
![Toby Schachman - Shadershop (2014)](shadershop.png)

@ -13,7 +13,7 @@ The following code structure is going to be our fence. In it, we visualize the n
This code is your fence; it's important to observe and understand it. You will come back over and over to this space between *0.0* and *1.0*. You will master the art of blending and shaping this line.
This one-to-one relationship between *x* and *y* (or the brightness) is know as *linear interpolation*. From here we can use some mathematical functions to *shape* the line. For example we can raise *x* to the power of 5 to make a *curved* line.
This one-to-one relationship between *x* and *y* (or the brightness) is known as *linear interpolation*. From here we can use some mathematical functions to *shape* the line. For example we can raise *x* to the power of 5 to make a *curved* line.
<div class="codeAndCanvas" data="expo.frag"></div>
@ -93,7 +93,7 @@ At the end of the last exercise we introduced some new functions. Now its tim
### Advance shaping functions
[Golan Levin](http://www.flong.com/) has great documentation of more complex shaping functions that are extraordinarily helpful. Porting them to GLSL is a really smart move, to start builidng your own resource of snippets of code.
[Golan Levin](http://www.flong.com/) has great documentation of more complex shaping functions that are extraordinarily helpful. Porting them to GLSL is a really smart move, to start building your own resource of snippets of code.
* Polynomial Shaping Functions: [www.flong.com/texts/code/shapers_poly](http://www.flong.com/texts/code/shapers_poly/)

@ -2,10 +2,9 @@
## 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.
Ainda não tivemos a chance de conversar sobre os tipos de vetores em GLSL. Mas antes de seguirmos adiante, é importante aprender mais sobre estas variáveis e o tópico de cores é uma ótima forma de os entendermos melhor.
Se você está familiarizado com os paradigmas de programação orientada a objetos, você provavelmente tenha percebido que estamos acessando dados dentro de vetores como qualquer `struct` em C.
```glsl
vec3 red = vec3(1.0,0.0,0.0);
@ -14,9 +13,9 @@ 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]`.
Definir cores usando a notação *x*, *y* e *z* pode ser confuso, certo? Por esta razão, existem outras formas de acessar esta mesma informação mas com nomes diferentes. Os valores de `.x`, `.y` e `.z` podem também ser chamados de `.r`, `.g` e `.b`, e também, .`s`, `.t` e `.p`. (.`s`, `.t` e `.p`. normalmente são usados para coordenadas espaciais de uma textura, na qual veremos mais tarde em outro capítulo). Você pode também acessar os dados de um vetor usando o índice de posição: `[0]`, `[1]` e `[2]`.
As seguintes linhas mostram todos os modos de acessar o mesmo dado:
As próximas linhas mostram todas as formas de acessar os mesmos dados:
```glsl
vec4 vector;
@ -26,27 +25,27 @@ 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.
Essas formas diferentes de apontar para variáveis dentro de vetores são apenas nomenclaturas criadas para ajudar você a criar um código mais limpo. Esta flexibilidade embutida em linguagem de shader é a porta para começar a pensar alternadamente em cores e coordenadas espaciais.
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*.
Outro ótima característica dos tipos vetoriais em GLSL é que as propriedades podem ser combinadas em qualquer ordem, o que facilita a manipulação dos valores. Esta 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
// Making Yellow
yellow.rg = vec2(1.0); // Assigning 1. to red and green channels
yellow[2] = 0.0; // Assigning 0. to blue channel
// Fazendo o Magenta
magenta = yellow.rbg; // Definindo os canais com green e blue trocados
// Making Magenta
magenta = yellow.rbg; // Assign the channels with green and blue swapped
// Fazendo o Verde
green.rgb = yellow.bgb; // Definindo o canal blue do Yellow (0) para os canais red e blue
// Making Green
green.rgb = yellow.bgb; // Assign the blue channel of Yellow (0) to red and blue channels
```
#### 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):
Você pode não estar acostumado a escolher cores com números - isso pode ser bem não intuitivo. Felizmente, existem inúmeros excelentes programas que facilitarão seu trabalho. Encontre um que atende as suas necessidades e então pratique para conseguir entregar cores em `vec3` ou `vec4`. Por exemplo, aqui está os templates que uso no [Spectrum](http://www.eigenlogik.com/spectrum/mac):
```
vec3({{rn}},{{gn}},{{bn}})
@ -55,91 +54,90 @@ 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!
Agora que você sabe como cores são definidas, chegou a hora de integrar isso com nosso conhecimento prévio. Em GLSL, existe uma função muito útil chamada [`mix()`](../glossary/?search=mix), que permite que você misture dois valores em porcentagens. Você consegue adivinhar em qual intervalo esta porcentagem é? Sim, estes valores vão de 0.0 a 1.0! O que é perfeito para você, depois destas longas horas praticando seus movimentos de karatê na 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`.
Dê uma olhada na linha 18 do código a seguir e veja se nós conseguimos usar valores absolutos de uma onda seno pelo tempo para misturar `colorA` e `colorB`.
<div class="codeAndCanvas" data="mix.frag"></div>
Demonstre suas habilidades, fazendo isso:
Mostre suas habilidades ao:
* 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.
* Fazer uma transição expressiva entre as cores. Pense em uma emoção em particular, qual cor parece representá-la melhor? Como ela aparece? Como ela se esvai? Pense em outra emoção e determine uma cor para ela. Mude as cores do início de do final no código acima para corresponder aquelas emoções. Então, anime a transição usando funções. Robert Penner desenvolveu uma série sobre funções populares para animação computacional conhecido como [funções de suavização](http://easings.net/). você pode usar [este exemplo](../edit.php#06/easing.frag) como pesquisa e inspiração mas os melhores resultados virão das suas próprias funções.
### Brincando com gradientes
### Experimentando com degradês
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`.
A função [`mix()`](../glossary/?search=mix) tem mais a oferecer. Ao invés de passar um único `float`, nós podemos passar uma variável do tipo que correspondente aos dois primeiros argumentos, neste caso, uma `vec3`. Fazendo isso, nós ganhamos controle sobre a porcentagem de mesclagem para cada canal de cor 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.
Dê uma olhada no exemplo a seguir. Como os exemplos no capítulo anterior, nós estamos encaixando a transição na coordenada *x* normalizada e a visualizando com uma linha. Agora todos os canais seguem esta 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.
Agora, descomente a linha de número 25 e veja o que acontece. Então tente descomentar as linhas 26 e 27. Lembre-se que as linhas representam a intensidade de `colorA` e `colorB` a serem 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:
Você provavelmente reconheceu os três modelos de funções que estamos usando nas linhas 25 a 27. Explore com eles! Agora é hora para experimentar e exibir suas habilidades do capítulo anterior e criar 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
* Componha um gradiente que se assemelha com entardecer de William Turner
* Animar uma transição entre um nascer e um pôr do sol, usando `u_time`.
* Anime uma transição entre o nascer do sol e o pôr do sol usando `u_time`.
* Você consegue fazer um arco-íris com o que aprendemos até agora?
* Você consegue criar um arco-íris usando o que foi aprendido 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.
Nós não podemos falar sobre cores sem mencionar o espaço de cores. Como você provavelmente sabe, existem diferentes formas de organizar cores além de 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.
[HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) vem de Hue(Matiz), Saturation(Saturação) e Brightness (Brilho ou Valor) e é uma forma muito mais intuitiva e útil de organizar cores. Pare 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.
Mapeando a posição no eixo x para a matiz e a posição no eixo y para brilho, nós obtemos um lindo espectro de cores visíveis. Esta distribuição espacial de cores pode ser muito útil; é muito mais intuitivo para escolher 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)`).
### HSB em coordenadas populares
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.
HSB foi originalmente criada para ser representada em coordenadas polares (baseada em ângulo e raio) ao invés de coordenadas cartesianas (baseadas em x e y). Para mapear nossa função de HSB em coordenadas polares, precisamos obter o ângulo e a distância do centro da tela para a coordenada do píxel. Para isso, usaremos a função [`length()`](../glossary/?search=length) e [`atan(y,x)`](../glossary/?search=atan) (que é uma versão GLSL da comumente usada `atan2(y,x)`).
Ao utilizar vetores e funções trigonométricas, `vec2`, `vec3` e `vec4` são tratados como vetores mesmo quando elas representam cores. Nós começaremos a tratar cores e vetores de forma similar e você verá que esta flexibilidade conceitual é muito poderosa.
**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).
**Nota:** Se você estiver 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). Também em GLSL tem funções relacionais especiais para vetorais 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.
Uma vez que obtemos o ângulo e a tamanho, precisamos "normalizar" seus valores para o intervalo entre 0.0 e 1.0. Na linha 27, [`atan(y,x)`](../glossary/?search=atan) retornará um ângulo em radianos entre -PI e PI (-3.14 a 3.14), então precisamos dividir este número por `TWO_PI` (definido no topo do código) para obtermos valores entre -0.5 até 0.5, que, com uma simples adição, nós mudamos para o intervalo desejado de 0.0 a 1.0. O raio retornará um máximo de 0.5 (porque nós estamos calculando a distância a partir do centro da tela), então nós precisamos dobrar este intervalo (multiplicando por dois) para obter um 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.
Como você pode observar, nosso jogo aqui é sobre transformar e mapear intervalos para 0.0 a 1.0 que 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.
* Modifique o exemplo de coordenadas polares para obter uma roda de cores que gira, assim como 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.
* Use a modelagem de função junto com a função de conversão de HSB para RGB para expandir um valor da matiz em particular e comprimir 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.]
* Se você olhar de perto na roda de cores usada em seletores de cor (veja a imagem abaixo), elas usam um diferente espectro de acordo com o espaço de cores em RYB. Por exemplo, a cor oposta ao vermelho deve ser verde, mas no nosso exemplo é ciano. Você consegue encontrar um jeito de consertar isso para parecer exatamente com a imagem a baixo? [Dica: este é um grande momento para usar modelagem de funções.]
![](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.
* Leia [Josef Albers' book Interaction of Color](http://www.goodreads.com/book/show/111113.Interaction_of_Color) (EM INGLÊS) e use os seguintes exemplos de shader 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.
Antes de irmos para o próximo capítulo, vamos parar e rebobinar. Volte e dê uma olhada nas funções nos exemplos anteriores. Você vai perceber um `in` antes dos tipos de argumentos. Isso é um *qualificador*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier) e neste caso, especifica que a variável é somente leitura. Em exemplos futuros, veremos que também é possível definir argumentos como `out` ou `inout`. Este último, `inout`, é conceitualmente similar a passar um argumento pela referência na qual 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.
Você pode não acreditar, mas agora nós temos todos os elementos para fazer desenhos legais. No próximo capítulo, aprenderemos como combinar todos os truques para criar formas geométricas *mesclando* o espaço. Isso mesmo... *mesclando* espaço.

@ -235,4 +235,6 @@ pct = pow(distance(st,vec2(0.4)),distance(st,vec2(0.6)));
恭喜!你完成了最艰难的部分!休息下让这些概念沉淀一下吧 —— 用Processing 来画简单的形状很容易,但却不到火候。在 shader 的世界里,画形状是很纠结,而且适应这种新的编程范式会有些累人。
在本章的最后,您将找到[PixelSpirit Deck]https://patriciogonzalezvivo.github.io/PixelSpiritDeck/的链接这组卡片将帮助您学习新的SDF功能将其组合到您的设计和使用中 在您的着色器上。 卡片组具有预先的学习曲线,因此,每天拿一张卡片并进行练习将推动并挑战您几个月的技能。
既然现在你知道了如何画形状,我十分肯定你脑袋里已经充满了新的点子。在接下来的章节里你会学习到怎么移动,旋转以及缩放图形。这将使你的创作如虎添翼!

@ -230,4 +230,6 @@ Unser Trick nutzt die gegebene Anzahl der Seiten eines Polygons, um das benötig
Herzlichen Glückwunsch! Du hast Dich durch schwieriges Fahrwasser gekämpft. Nimm eine kleine Pause, damit sich das Erlernte setzen kann. Das Zeichnen komplexer Formen im Land der Shader ist wahrlich nicht ganz trivial, das kann durchaus ein wenig erschöpfen.
Unten am Ende dieses Kapitels finden Sie einen Link zu [PixelSpirit Deck] (https://patriciogonzalezvivo.github.io/PixelSpiritDeck/). Mit diesem Kartenspiel können Sie neue SDF-Funktionen erlernen, in Ihre Designs einfügen und verwenden auf deine Shader. Das Deck hat eine prägresive Lernkurve. Wenn Sie also eine Karte pro Tag nehmen und daran arbeiten, können Sie Ihre Fähigkeiten monatelang verbessern und herausfordern.
Da Du nun weißt, wie man unterschiedliche Formen zeichnet, kommen Dir bestimmt viele interessante Ideen in den Sinn. In den folgenden Kapiteln lernen wir, wie man Formen verschieben, skalieren und rotieren kann. Das wird Dir ermöglichen, komplexe Kompositionen zu erstellen.

@ -288,5 +288,7 @@ Faites une pause et laissez décanter ces nouveaux concepts.
Dessiner des formes dans une API de dessin, c'est facile mais ici c'est une autre histoire.
Au pays des shaders, dessiner des formes géométriques est un peu tordu et s'imposer la disciple nécessaire à la compréhension de ce paradigme est épuisant.
À la fin de ce chapitre, vous trouverez un lien vers [PixelSpirit Deck] (https://patriciogonzalezvivo.github.io/PixelSpiritDeck/). Ce jeu de cartes vous aidera à apprendre les nouvelles fonctions SDF, à les composer dans vos conceptions et à les utiliser. sur vos shaders. La plate-forme a une courbe dapprentissage prégressive, aussi prendre une carte par jour et travailler dessus vous poussera et mettra au défi vos compétences pendant des mois.
Maintenant que vous savez comment dessiner des formes, je suis sûr que ça va vous donner des idées.
Au prochain chapitre, nous apprendrons à déplacer, à appliquer des rotations et à changer d'échelle pour créer des compositions !

@ -227,4 +227,6 @@ Il nostro trucco userà il numero di lati di un poligono per costruire il campo
Congratulazioni! Avete affrontato la parte più complicata! Fate una pausa per poter assimilare questi concetti: disegnare delle semplici forme con Processing è facile, ma qui no. Nella “terra degli Shader”, disegnare le forme è contorto e può essere faticoso adattarsi al nuovo paradigma di codificazione.
Alla fine di questo capitolo troverai un link a [PixelSpirit Deck] (https://patriciogonzalezvivo.github.io/PixelSpiritDeck/) questo mazzo di carte ti aiuterà ad apprendere nuove funzioni SDF, compilarle nei tuoi progetti e utilizzarle sui tuoi shader. Il mazzo ha una curva di apprendimento pregresiva, quindi prendere una carta al giorno e lavorarci su spingerà e metterà alla prova le tue abilità per mesi.
Ora che sapete come disegnare le forme, sono sicuro che vi verranno in mente nuove idee. Nel capitolo successivo imparerete a spostare, ruotare e ridimensionare le forme. Questo vi permetterà di fare delle composizioni!

@ -237,4 +237,6 @@ pct = pow(distance(st,vec2(0.4)),distance(st,vec2(0.6)));
おめでとうございます。これで山を乗り越えました。[Processing](https://processing.org/)を使えばシンプルな形を描くのは簡単なことですが、ここで学んだ方法は違います。シェーダーの世界では形を描くのにもひねくれたやり方をしなくてはなりませんし、新しいコーディングの考え方に慣れるのは大変なことです。一息入れて、学んだ概念を頭に馴染ませましょう。
この章の終わりには、[PixelSpirit Deck]https://patriciogonzalezvivo.github.io/PixelSpiritDeck/へのリンクがあります。このカードのデッキは、新しいSDF機能を学び、デザインに組み込んで使用するのに役立ちます シェーダーで。 このデッキには学習曲線がありますので、1日に1枚のカードを取り、それに取り組んでいくと、数か月間スキルが向上します。
図形の描きかたを学んだので、新しいアイデアが頭の中に浮かんでくることでしょう。次の章ではこれらを移動、回転、そして拡大・縮小させる方法を学びます。これで図形を様々に組み合わせることができるようになります。

@ -228,4 +228,6 @@ float a = atan(pos.y,pos.x);
Поздравляю! Мы прошли трудную тему! Вдохните и дайте изученным принципам устояться. Рисовать фигуры - это просто в Processing, но не здесь. В мире шейдеров алгоритмы рисования фигур очень заковыристы, и адаптация к такой парадигме программирования может стоить значительных усилий.
В конце этой главы вы найдете ссылку на [PixelSpirit Deck] (https://patriciogonzalezvivo.github.io/PixelSpiritDeck/), эта колода карт поможет вам изучить новые функции SDF, объединить их в свои проекты и использовать на ваших шейдерах. Колода имеет предварительную кривую обучения, поэтому, взяв одну карту в день и работая над ней, вы испытаете свои навыки на месяцы.
Теперь, когда вы умеете рисовать фигуры, новые идеи будут появляться в вашей голове с огромной скоростью. В следующей главе мы научимся двигать, вращать и масштабировать фигуры. Вы сможете делать композиции!

@ -228,4 +228,6 @@ The trick will use the number of edges of a polygon to construct the distance fi
Congratulations! You have made it through the rough part! Take a break and let these concepts settle - drawing simple shapes in Processing is easy but not here. In shader-land drawing shapes is twisted, and it can be exhausting to adapt to this new paradigm of coding.
Down at the end of this chapter you will find a link to [PixelSpirit Deck](https://patriciogonzalezvivo.github.io/PixelSpiritDeck/) this deck of cards will help you learn new SDF functions, compose them into your designs and use on your shaders. The deck have a pregresive learning curve, so taking one card a day and working on it will push and challenge your skills for months.
Now that you know how to draw shapes I'm sure new ideas will pop into your mind. In the following chapter you will learn how to move, rotate and scale shapes. This will allow you to make compositions!

@ -21,6 +21,259 @@
echo $Parsedown->text(file_get_contents($README.'.md'));
echo '
<div id="product-component-1573172983507"></div>
<script type="text/javascript">
/*<![CDATA[*/
(function () {
var scriptURL = "https://sdks.shopifycdn.com/buy-button/latest/buy-button-storefront.min.js";
if (window.ShopifyBuy) {
if (window.ShopifyBuy.UI) {
ShopifyBuyInit();
} else {
loadScript();
}
} else {
loadScript();
}
function loadScript() {
var script = document.createElement("script");
script.async = true;
script.src = scriptURL;
(document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(script);
script.onload = ShopifyBuyInit;
}
function ShopifyBuyInit() {
var client = ShopifyBuy.buildClient({
domain: "pixelspirit.myshopify.com",
storefrontAccessToken: "686544ffb4b575bec76a775b422b5d72",
});
ShopifyBuy.UI.onReady(client).then(function (ui) {
ui.createComponent("product", {
id: "8723521601",
node: document.getElementById("product-component-1573172983507"),
moneyFormat: "%24%7B%7Bamount%7D%7D",
options: {
"product": {
"styles": {
"product": {
"@media (min-width: 601px)": {
"max-width": "100%",
"margin-left": "0",
"margin-bottom": "50px"
},
"text-align": "left"
},
"title": {
"font-family": "Baskerville, serif",
"font-weight": "normal",
"font-size": "26px"
},
"button": {
"font-size": "16px",
"padding-top": "16px",
"padding-bottom": "16px",
":hover": {
"background-color": "#000000"
},
"background-color": "#000000",
":focus": {
"background-color": "#000000"
},
"padding-left": "26px",
"padding-right": "26px"
},
"quantityInput": {
"font-size": "16px",
"padding-top": "16px",
"padding-bottom": "16px"
},
"price": {
"font-family": "Baskerville, serif",
"font-size": "18px"
},
"compareAt": {
"font-family": "Baskerville, serif",
"font-size": "15.299999999999999px"
},
"description": {
"font-family": "Baskerville, serif"
}
},
"buttonDestination": "checkout",
"layout": "horizontal",
"contents": {
"img": false,
"imgWithCarousel": true,
"description": true
},
"width": "100%",
"text": {
"button": "Buy now"
}
},
"productSet": {
"styles": {
"products": {
"@media (min-width: 601px)": {
"margin-left": "-20px"
}
}
}
},
"modalProduct": {
"contents": {
"img": false,
"imgWithCarousel": true,
"button": false,
"buttonWithQuantity": true
},
"styles": {
"product": {
"@media (min-width: 601px)": {
"max-width": "100%",
"margin-left": "0px",
"margin-bottom": "0px"
}
},
"button": {
"font-size": "16px",
"padding-top": "16px",
"padding-bottom": "16px",
":hover": {
"background-color": "#000000"
},
"background-color": "#000000",
":focus": {
"background-color": "#000000"
},
"padding-left": "26px",
"padding-right": "26px"
},
"quantityInput": {
"font-size": "16px",
"padding-top": "16px",
"padding-bottom": "16px"
}
}
},
"cart": {
"styles": {
"button": {
"font-size": "16px",
"padding-top": "16px",
"padding-bottom": "16px",
":hover": {
"background-color": "#000000"
},
"background-color": "#000000",
":focus": {
"background-color": "#000000"
}
},
"title": {
"color": "#4c4c4c"
},
"header": {
"color": "#4c4c4c"
},
"lineItems": {
"color": "#4c4c4c"
},
"subtotalText": {
"color": "#4c4c4c"
},
"subtotal": {
"color": "#4c4c4c"
},
"notice": {
"color": "#4c4c4c"
},
"currency": {
"color": "#4c4c4c"
},
"close": {
"color": "#4c4c4c",
":hover": {
"color": "#4c4c4c"
}
},
"empty": {
"color": "#4c4c4c"
},
"noteDescription": {
"color": "#4c4c4c"
},
"discountText": {
"color": "#4c4c4c"
},
"discountIcon": {
"fill": "#4c4c4c"
},
"discountAmount": {
"color": "#4c4c4c"
}
}
},
"toggle": {
"styles": {
"toggle": {
"background-color": "#000000",
":hover": {
"background-color": "#000000"
},
":focus": {
"background-color": "#000000"
}
},
"count": {
"font-size": "16px"
}
}
},
"lineItem": {
"styles": {
"variantTitle": {
"color": "#4c4c4c"
},
"title": {
"color": "#4c4c4c"
},
"price": {
"color": "#4c4c4c"
},
"fullPrice": {
"color": "#4c4c4c"
},
"discount": {
"color": "#4c4c4c"
},
"discountIcon": {
"fill": "#4c4c4c"
},
"quantity": {
"color": "#4c4c4c"
},
"quantityIncrement": {
"color": "#4c4c4c",
"border-color": "#4c4c4c"
},
"quantityDecrement": {
"color": "#4c4c4c",
"border-color": "#4c4c4c"
},
"quantityInput": {
"color": "#4c4c4c",
"border-color": "#4c4c4c"
}
}
}
},
});
});
}
})();
/*]]>*/
</script>
</div>
<hr>
<ul class="navigationBar" >

@ -118,5 +118,5 @@ Fazer padrões procedurais é um exercício mentar para encontrar elementos mín
![Franz Sales Meyer - A handbook of ornament (1920)](geometricpatters.png)
Com este capítulo, terminamos a seção sobre Desenho Algorítmico. Nos capítulos seguintes vamos aprender como trazer alguma entropia para nossos shaders e produzir designs geradores.
Com este capítulo, terminamos a seção sobre Desenho Algorítmico. Nos capítulos seguintes vamos aprender como trazer alguma entropia para nossos shaders e produzir designs generativos.

@ -0,0 +1,92 @@
# Designs Generativos
It is not a surprise that after so much repetition and order the author is forced to bring some chaos.
## Random
[![Ryoji Ikeda - test pattern (2008) ](ryoji-ikeda.jpg) ](http://www.ryojiikeda.com/project/testpattern/#testpattern_live_set)
Randomness is a maximal expression of entropy. How can we generate randomness inside the seemingly predictable and rigid code environment?
Let's start by analyzing the following function:
<div class="simpleFunction" data="y = fract(sin(x)*1.0);"></div>
Above we are extracting the fractional content of a sine wave. The [```sin()```](../glossary/?search=sin) values that fluctuate between ```-1.0``` and ```1.0``` have been chopped behind the floating point, returning all positive values between ```0.0``` and ```1.0```. We can use this effect to get some pseudo-random values by "breaking" this sine wave into smaller pieces. How? By multiplying the resultant of [```sin(x)```](../glossary/?search=sin) by larger numbers. Go ahead and click on the function above and start adding some zeros.
By the time you get to ```100000.0``` ( and the equation looks like this: ```y = fract(sin(x)*100000.0)``` ) you aren't able to distinguish the sine wave any more. The granularity of the fractional part has corrupted the flow of the sine wave into pseudo-random chaos.
## Controlling chaos
Using random can be hard; it is both too chaotic and sometimes not random enough. Take a look at the following graph. To make it, we are using a ```rand()``` function which is implemented exactly like we describe above.
Taking a closer look, you can see the [```sin()```](../glossary/?search=sin) wave crest at ```-1.5707``` and ```1.5707```. I bet you now understand why - it's where the maximum and minimum of the sine wave happens.
If look closely at the random distribution, you will note that the there is some concentration around the middle compared to the edges.
<div class="simpleFunction" data="y = rand(x);
//y = rand(x)*rand(x);
//y = sqrt(rand(x));
//y = pow(rand(x),5.);"></div>
A while ago [Pixelero](https://pixelero.wordpress.com) published an [interesting article about random distribution](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/). I've added some of the functions he uses in the previous graph for you to play with and see how the distribution can be changed. Uncomment the functions and see what happens.
If you read [Pixelero's article](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/), it is important to keep in mind that our ```rand()``` function is a deterministic random, also known as pseudo-random. Which means for example ```rand(1.)``` is always going to return the same value. [Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/) makes reference to the ActionScript function ```Math.random()``` which is non-deterministic; every call will return a different value.
## 2D Random
Now that we have a better understanding of randomness, it's time to apply it in two dimensions, to both the ```x``` and ```y``` axis. For that we need a way to transform a two dimensional vector into a one dimensional floating point value. There are different ways to do this, but the [```dot()```](../glossary/?search=dot) function is particulary helpful in this case. It returns a single float value between ```0.0``` and ```1.0``` depending on the alignment of two vectors.
<div class="codeAndCanvas" data="2d-random.frag"></div>
Take a look at lines 13 to 15 and notice how we are comparing the ```vec2 st``` with another two dimensional vector ( ```vec2(12.9898,78.233)```).
* Try changing the values on lines 14 and 15. See how the random pattern changes and think about what we can learn from this.
* Hook this random function to the mouse interaction (```u_mouse```) and time (```u_time```) to understand better how it works.
## Using the chaos
Random in two dimensions looks a lot like TV noise, right? It's a hard raw material to use to compose images. Let's learn how to make use of it.
Our first step is to apply a grid to it; using the [```floor()```](../glossary/?search=floor) function we will generate an integer table of cells. Take a look at the following code, especially lines 22 and 23.
<div class="codeAndCanvas" data="2d-random-mosaic.frag"></div>
After scaling the space by 10 (on line 21), we separate the integers of the coordinates from the fractional part. We are familiar with this last operation because we have been using it to subdivide a space into smaller cells that go from ```0.0``` to ```1.0```. By obtaining the integer of the coordinate we isolate a common value for a region of pixels, which will look like a single cell. Then we can use that common integer to obtain a random value for that area. Because our random function is deterministic, the random value returned will be constant for all the pixels in that cell.
Uncomment line 29 to see that we preserve the floating part of the coordinate, so we can still use that as a coordinate system to draw things inside each cell.
Combining these two values - the integer part and the fractional part of the coordinate - will allow you to mix variation and order.
Take a look at this GLSL port of the famouse ```10 PRINT CHR$(205.5+RND(1)); : GOTO 10``` maze generator.
<div class="codeAndCanvas" data="2d-random-truchet.frag"></div>
Here I'm using the random values of the cells to draw a line in one direction or the other using the ```truchetPattern()``` function from the previous chapter (lines 41 to 47).
You can get another interesting pattern by uncommenting the block of lines between 50 to 53, or animate the pattern by uncommenting lines 35 and 36.
## Master Random
[Ryoji Ikeda](http://www.ryojiikeda.com/), Japanese electronic composer and visual artist, has mastered the use of random; it is hard not to be touched and mesmerized by his work. His use of randomness in audio and visual mediums is forged in such a way that it is not annoying chaos but a mirror of the complexity of our technological culture.
<iframe src="https://player.vimeo.com/video/76813693?title=0&byline=0&portrait=0" width="800" height="450" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
Take a look at [Ikeda](http://www.ryojiikeda.com/)'s work and try the following exercises:
* Make rows of moving cells (in opposite directions) with random values. Only display the cells with brighter values. Make the velocity of the rows fluctuate over time.
<a href="../edit.php#10/ikeda-00.frag"><canvas id="custom" class="canvas" data-fragment-url="ikeda-00.frag" width="520px" height="200px"></canvas></a>
* Similarly make several rows but each one with a different speed and direction. Hook the position of the mouse to the threshold of which cells to show.
<a href="../edit.php#10/ikeda-03.frag"><canvas id="custom" class="canvas" data-fragment-url="ikeda-03.frag" width="520px" height="200px"></canvas></a>
* Create other interesting effects.
<a href="../edit.php#10/ikeda-04.frag"><canvas id="custom" class="canvas" data-fragment-url="ikeda-04.frag" width="520px" height="200px"></canvas></a>
Using random aesthetically can be problematic, especially if you want to make natural-looking simulations. Random is simply too chaotic and very few things look ```random()``` in real life. If you look at a rain pattern or a stock chart, which are both quite random, they are nothing like the random pattern we made at the begining of this chapter. The reason? Well, random values have no correlation between them what so ever, but most natural patterns have some memory of the previous state.
In the next chapter we will learn about noise, the smooth and *natural looking* way of creating computational chaos.

@ -12,8 +12,8 @@ vec2 random2(vec2 st){
return -1.0 + 2.0*fract(sin(st)*43758.5453123);
}
// Value Noise by Inigo Quilez - iq/2013
// https://www.shadertoy.com/view/lsf3WH
// Gradient Noise by Inigo Quilez - iq/2013
// https://www.shadertoy.com/view/XdXGW8
float noise(vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);

@ -18,8 +18,8 @@ vec2 random2(vec2 st){
return -1.0 + 2.0*fract(sin(st)*43758.5453123);
}
// Value Noise by Inigo Quilez - iq/2013
// https://www.shadertoy.com/view/lsf3WH
// Gradient Noise by Inigo Quilez - iq/2013
// https://www.shadertoy.com/view/XdXGW8
float noise(vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);

@ -12,8 +12,8 @@ vec2 random2(vec2 st){
return -1.0 + 2.0*fract(sin(st)*43758.5453123);
}
// Value Noise by Inigo Quilez - iq/2013
// https://www.shadertoy.com/view/lsf3WH
// Gradient Noise by Inigo Quilez - iq/2013
// https://www.shadertoy.com/view/XdXGW8
float noise(vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);

@ -12,8 +12,8 @@ vec2 random2(vec2 st){
return -1.0 + 2.0*fract(sin(st)*43758.5453123);
}
// Value Noise by Inigo Quilez - iq/2013
// https://www.shadertoy.com/view/lsf3WH
// Gradient Noise by Inigo Quilez - iq/2013
// https://www.shadertoy.com/view/XdXGW8
float noise(vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 144 KiB

@ -1,3 +1,5 @@
.PHONY: default clean all epub pdf tex
default: clean all
clean:
@ -6,4 +8,13 @@ clean:
rm -rf book.*
all:
python2.7 src/parseBook.py
python2.7 src/parseBook.py -f tex -f pdf -f epub
epub:
python2.7 src/parseBook.py -f epub
pdf:
python2.7 src/parseBook.py -f pdf
tex:
python2.7 src/parseBook.py -f tex

@ -1,109 +1,111 @@
<canvas id="custom" class="canvas" data-fragment-url="src/moon/moon.frag" data-textures="src/moon/moon.jpg" width="350px" height="350px"></canvas>
# The Book of Shaders
*by [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) and [Jen Lowe](http://jenlowe.net/)*
*por [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) e [Jen Lowe](http://jenlowe.net/)*
Este é um guia passo a passo através do universo complexo e abstrato dos Fragment Shaders.
Este é um guia passo-a-passo pelo universo abstrato e complexo de Fragment Shaders.
<div class="header">
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=B5FSVSHGEATCG" style="float: right;"><img src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif" alt=""></a>
</div>
## Contents
## Conteúdo
* [Sobre este livro](00/)
* Começando
* Início
* [O que é um shader?](01/)
* [Hello world!”](02/)
* [Uniformes](03/)
* [Olá mundo!”](02/)
* [Uniforms](03/)
* [Executando seu shader](04/)
* Desenho algorítmico
* Desenho algorítmico
* [Funções de forma](05/)
* [Cores](06/)
* [Formas](07/)
* [Matrizes](08/)
* [Padrões](09/)
* Designs generativos
* [Aletório](10/)
* [Ruído](11/)
* [Ruído celular](12/)
* [Movimento browniano fractal](13/)
* Design generativo
* [Aleatório](10/)
* [Noise](11/)
* [Cellular noise](12/)
* [Movimento browniano fracionário](13/)
* Fractais
* Processamento de imagem
* Texturas
* Operações com imagens
* Convoluções núcleo (kernel
* Operações de imagem
* Convoluções do kernel
* Filtros
* Outros efeitos
* Simulação
* Pingpong
* Conway
* Ripples
* Cor de água
* Difusão de reação
* Ondulações
* Aquarela
* Reação-Difusão
* Gráficos 3D
* Gráficos em 3D
* Luzes
* Normal-maps
* Bump-maps
* Ray marching
* Environmental-maps (esféricas e cúbicas)
* Environmental-maps (esférico e cúbico)
* Reflexão e refração
* [Apêndice:](appendix/) Outras formas de usar este livro
* [Como posso navegar esse livro offline?](appendix/00/)
* [Como rodar os exemplo em um Raspberry Pi?](appendix/01/)
* [Como imprimir esse livro?](appendix/02/)
* [Como posso colaborar?](appendix/03/)
* [Uma introdução para quem vem do JS](appendix/04/) por [Nicolas Barradeau](http://www.barradeau.com/)
* [Como eu posso ler este livro offline?](appendix/00/)
* [Como eu posso rodar os exemplos em um Raspberry Pi?](appendix/01/)
* [Como imprimir este livro?](appendix/02/)
* [Como eu posso colaborar?](appendix/03/)
* [Uma introdução para quem é familiarizado com JS](appendix/04/) por [Nicolas Barradeau](http://www.barradeau.com/)
* [Galeria de Exemplos](examples/)
* [Galeria de exemplos](examples/)
* [Glossário](glossary/)
## Sobre os Autores
## Sobre os autores
[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentina) é um artista e desenvolvedor, atualmente morando em New York. Ele explora os espaços entre o orgânico e sintético, analógico e digital, individual e coletivo. Em seu trabalho, ele usa código como linguagem de expressão com a intenção de desenvolver uma melhor união.
[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentina) é um artista e desenvolvedor residente em New York. Ele explora os espaços intersticiais entre o orgânico e sintético, analógico e digital, individual e coletivo. Em seu trabalho utiliza código como linguagem expressiva com a intenção de desenvolver uma melhor conexão entre as pessoas.
Patricio estudou e praticou psicoterapia e terapia em arte expressiva. Tem um MFA em Design & Tecnologia pela Parsons The New School, onde ele agora leciona. Atualmente ele trabalha como Engenheiro Gráfico na Mapzen criando ferramentas openSource de mapeamento.
Patricio estudou e praticou psicoterapia e terapia de arte expressiva. Ele possui MFA em Design & Technologia pela Parsons The New School, onde hoje leciona. Atualmente trabalha como Engenheiro Gráfico na Mapzen, criando ferramentas open source de mapeamento.
<div class="header"> <a href="http://patriciogonzalezvivo.com/" target="_blank">WebSite</a> - <a href="https://twitter.com/patriciogv" target="_blank">Twitter</a> - <a href="https://github.com/patriciogonzalezvivo" target="_blank">GitHub</a> - <a href="https://vimeo.com/patriciogv" target="_blank">Vimeo</a> - <a href="https://www.flickr.com/photos/106950246@N06/" target="_blank"> Flickr</a></div>
[Jen Lowe](http://jenlowe.net/) é uma cientista de dados independente e comunicadora de dados na Datatelling onde ela junta pessoas + números + palavras. Ela dá aulas no programa Design for Social Innovation da SVA, co-fundou a School for Poetic Computation, ensinou Matemática para Artistas na NYU ITP, pesquisouno Spatial Information Design Lab da Columbia University, e contribuiu com ideias na White House Office of Science and Technology Policy. Já falou na SXSW e Eyeo. Seu trabalho já foi coberto pelo The New York Times e a Fast Company. Sua pesquisa, escrita, e discurso exploram as promessas e implicações dos dados e a tecnologia na sociedade. Ela tem um B.S. em Matemática Aplicadae e Master's em Ciência da Informação. Geralmente em oposição a isso tudo, ela sempre está do lado do amor.
[Jen Lowe](http://jenlowe.net/) é uma cientista de dados independente e comunicadora de dados na Datatelling, onde une pessoas + números + palavras. Ela leciona no SVA's Design for Social Innovation program, co-fundou a School for Poetic Computation, ensinou Math for Artists na NYU ITP, pesquisou no Spatial Information Design Lab na Columbia University, e contribuiu com ideias na White House Office of Science and Technology Policy. Ela discursou no SXSW e Eyeo. Seu trabalho foi coberto pelo The New York Times e Fast Company. Sua pesquisa, escritos, e palestras exploram as promessas e implicações dos dados e da technologia na sociedade. Ela é bacharel em Matemática Aplicada e mestre em Ciência da Informação. Frequentemente oposicionista, ela está sempre do lado do amor.
<div class="header"> <a href="http://jenlowe.net/" target="_blank">WebSite</a> - <a href="https://twitter.com/datatelling" target="_blank">Twitter</a> - <a href="https://github.com/datatelling" target="_blank">GitHub</a></div>
## Agradecimentos
## Acknowledgements
Obrigado a [Scott Murray](http://alignedleft.com/) pela inspiração e conselhos.
Obrigado [Scott Murray](http://alignedleft.com/) pela inspiração e conselhos.
Obrigado a [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/) por contribuir com apoio, boas ideia e código.
Obrigado [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/) por contribuir com apoio, boas ideias e código.
Obrigado a [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) e [Sawako](https://twitter.com/sawakohome) pela [tradução japonesa (日本語訳)](?lan=jp)
Obrigado [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) e [Sawako](https://twitter.com/sawakohome) pela [tradução em Japonês (日本語訳)](?lan=jp)
Obrigado a [Tong Li](https://www.facebook.com/tong.lee.9484) e [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) pela [tradução chinesa (中文版)](?lan=ch)
Obrigado [Tong Li](https://www.facebook.com/tong.lee.9484) e [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) pela [tradução em Chinês (中文版)](?lan=ch)
Obrigado a [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) pela tradução [coreana (한국어)](?lan=kr)
Obrigado [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) pela [tradução em Koreano (한국어)](?lan=kr)
Obrigado a [Nahuel Coppero (Necsoft)](http://hinecsoft.com/) pela tradução [espanhola](?lan=es)
Obrigado [Nahuel Coppero (Necsoft)](http://hinecsoft.com/) pela [tradução em Espanhol (español)](?lan=es)
Obrigado a [Nicolas Barradeau](https://twitter.com/nicoptere) e [Karim Naaji](http://karim.naaji.fr/) pela tradução [francesa](?lan=fr)
Obrigado [Nicolas Barradeau](https://twitter.com/nicoptere) e [Karim Naaji](http://karim.naaji.fr/) pela [tradução em Francês (français)](?lan=fr)
Obrigado a [Andrea Rovescalli](https://www.earove.info) pela tradução [italiana](?lan=it)
Obrigado [Andrea Rovescalli](https://www.earove.info) pela [tradução em Italiano (italiano)](?lan=it)
Obrigado a [Michael Tischer](http://www.mitinet.de) pela tradução [alemã](?lan=de)
Obrigado [Michael Tischer](http://www.mitinet.de) pela [tradução em Alemão (deutsch)](?lan=de)
Obrigado a [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) pela tradução [russa](?lan=ru)
Obrigado [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) pela [tradução em Russo (russian)](?lan=ru)
Obrigado a todos que acreditaram nesse projeto e [contribuiram com acertos](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) ou doações.
Obrigado [Andy Stanton](https://andy.stanton.is/) por corrigir e melhorar [a pipeline para exportar pdf/epub](https://thebookofshaders.com/appendix/02/)
## Get new chapters
Obrigado a todos que acreditaram neste projeto e [contribuíram com correções](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) ou doações.
Assine as newsletters ou [siga no Twitter](https://twitter.com/bookofshaders)
## Receba novos capítulos
<form style="border:1px solid #ccc;padding:3px;text-align:center;" action="https://tinyletter.com/thebookofshaders" method="post" target="popupwindow" onsubmit="window.open('https://tinyletter.com/thebookofshaders', 'popupwindow', 'scrollbars=yes,width=800,height=600');return true"><a href="https://tinyletter.com/thebookofshaders"><p><label for="tlemail">Entre com seu email</label></p></a><p><input type="text" style="width:140px" name="email" id="tlemail" /></p><input type="hidden" value="1" name="embed"/><input type="submit" value="Subscribe" /><p><a href="https://tinyletter.com" target="_blank"></a></p></form>
Assine a newsletter ou [nos siga no Twitter](https://twitter.com/bookofshaders)
<form style="border:1px solid #ccc;padding:3px;text-align:center;" action="https://tinyletter.com/thebookofshaders" method="post" target="popupwindow" onsubmit="window.open('https://tinyletter.com/thebookofshaders', 'popupwindow', 'scrollbars=yes,width=800,height=600');return true"><a href="https://tinyletter.com/thebookofshaders"><p><label for="tlemail">Insira seu e-mail</label></p></a><p><input type="text" style="width:140px" name="email" id="tlemail" /></p><input type="hidden" value="1" name="embed"/><input type="submit" value="Enviar" /><p><a href="https://tinyletter.com" target="_blank"></a></p></form>

@ -92,6 +92,8 @@ Thanks [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) for the Korean [transla
Thanks [Nahuel Coppero (Necsoft)](http://hinecsoft.com/) for the Spanish [translation (español)](?lan=es)
Thanks [Raphaela Protásio](https://github.com/Rawphs) and [Lucas Mendonça](https://github.com/luuchowl) for the Portuguese [translation (portugues)](?lan=pt)
Thanks [Nicolas Barradeau](https://twitter.com/nicoptere) and [Karim Naaji](http://karim.naaji.fr/) for the French [translation (français)](?lan=fr)
Thanks [Andrea Rovescalli](https://www.earove.info) for the Italian [translation (italiano)](?lan=it)
@ -100,6 +102,8 @@ Thanks [Michael Tischer](http://www.mitinet.de) for the German [translation (deu
Thanks [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) for the Russian [translation (russian)](?lan=ru)
Thanks [Andy Stanton](https://andy.stanton.is/) for fixing and improving [the pdf/epub export pipeline](https://thebookofshaders.com/appendix/02/)
Thanks to everyone who has believed in this project and [contributed with fixes](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) or donations.
## Get new chapters

@ -10,15 +10,7 @@ For printing this book you need first to parse it. For that you will need [`glsl
In **MacOSX** get sure to have [homebrew](http://brew.sh/) installed and then on your terminal do:
```bash
brew update
brew upgrade
brew tap homebrew/versions
brew install glfw3
cd ~
git clone http://github.com/patriciogonzalezvivo/glslViewer.git
cd glslViewer
make
make install
brew install glslviewer
```
On **Raspberry Pi** you need to get [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), a Debian-based Linux distribution made for Raspberry Pi and then do:
@ -35,10 +27,16 @@ For parsing the Markdown chapters into Latex and then into a PDF file we will us
In **MacOSX**:
Download and Install [basictex & MacTeX-Additions](http://www.tug.org/mactex/morepackages.html) and then install [Pandoc](http://johnmacfarlane.net/pandoc/) and Python by:
Download and Install MacTeX by:
```bash
brew install pandoc python2.7
brew cask install mactex-no-gui
```
and then install [Pandoc](http://johnmacfarlane.net/pandoc/) and Python 2 by:
```bash
brew install pandoc python@2
```
On **Raspberry Pi** (Raspbian):
@ -57,7 +55,18 @@ For that open your terminal once again and type:
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make
make clean pdf
```
If everything goes well, you will see a `book.pdf` file which you can read on your favorite device or print.
#### Compile the book into an epub for use with an e-reader
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean epub
```
The generated `book.epub` can be used directly, or converted to a `.mobi` file for use with Kindle by using a converter, for example Calibre.

@ -1,6 +1,6 @@
<div class="header">
<p class="subtitle"><a href="https://thebookofshaders.com/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a> & <a href="http://jenlowe.net">Jen Lowe</a> </p>
<p> <a href="?lan=jp">日本</a> - <a href="?lan=ch">中文版</a> - <a href="?lan=kr">한국어</a> - <a href="?lan=es">Español</a> - <a href="?lan=fr">Français</a> - <a href="?lan=it">Italiano</a> - <a href="?lan=de">Deutsch</a> - <a href="?lan=ru">Русский</a> - <a href=".">English</a></p>
<p> <a href="?lan=jp">日本</a> - <a href="?lan=ch">中文版</a> - <a href="?lan=kr">한국어</a> - <a href="?lan=es">Español</a> - <a href="?lan=pt">Portugues</a> - <a href="?lan=fr">Français</a> - <a href="?lan=it">Italiano</a> - <a href="?lan=de">Deutsch</a> - <a href="?lan=ru">Русский</a> - <a href=".">English</a></p>
</div>
<hr>

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.

@ -0,0 +1,5 @@
<dc:title>The Book of Shaders</dc:title>
<dc:language>en-US</dc:language>
<dc:creator opf:file-as="Gonzalez Vivo, Patricio" opf:role="aut">Patricio Gonzalez Vivo</dc:creator>
<dc:creator opf:file-as="Lowe, Jen" opf:role="aut">Jen Lowe</dc:creator>
<dc:rights>Copyright 2015 by Patricio Gonzalez Vivo &amp; Jen Lowe</dc:rights>

@ -13,7 +13,7 @@ vec4 cos(vec4 angle)
```angle``` specify the quantity, in radians, of which to return the cosine.
### Description
```cos()``` returns the trigonometric sine of angle.
```cos()``` returns the trigonometric cosine of angle.
<div class="simpleFunction" data="y = cos(x); "></div>

@ -4,6 +4,12 @@ import os
import os.path
import re
import subprocess
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--format", action='append', choices=['tex', 'pdf', 'epub'], type=str.lower, required=True)
parser.add_argument("--skip-image-generation", help="skip image generation", action="store_true")
args = parser.parse_args()
latexEngine = "xelatex"
@ -12,12 +18,9 @@ outputPath = "."
if not os.path.exists(outputPath):
os.makedirs(outputPath)
pdfBookPath = os.path.join(outputPath, "book.pdf")
texBookPath = os.path.join(outputPath, "book.tex")
chapters = []
def injectShaderBlocks(_folder, _text):
rta = ""
lines = _text.split('\n')
@ -42,9 +45,10 @@ def injectShaderBlocks(_folder, _text):
shaderImage = folder + "/tmp-" + shaderName + ".png"
shaderCommand = "glslViewer " + shaderPath + " " + \
" ".join(shaderTexturePaths) + \
" -s 0.5 -o " + shaderImage
" -s 0.5 --headless -o " + shaderImage
print shaderCommand
returnCode = subprocess.call(shaderCommand, shell=True)
if not args.skip_image_generation:
returnCode = subprocess.call(shaderCommand, shell=True)
rta += "![](" + shaderImage + ")\n"
elif line.find('.gif') >= 0:
gifPath = re.sub(r'\!\[.*\]\((.*\.gif)\)', r'\1', line.rstrip())
@ -52,7 +56,8 @@ def injectShaderBlocks(_folder, _text):
pngImage = gifName + ".png"
convertCommand = "convert " + gifPath + " " + pngImage
print convertCommand
returnCode = subprocess.call(convertCommand, shell=True)
if not args.skip_image_generation:
returnCode = subprocess.call(convertCommand, shell=True)
rta += re.sub(r'\!\[(.*)\]\((.*)\.gif\)',
r'![\1](\2-0.png)', line) + '\n'
else:
@ -83,36 +88,33 @@ for folder in folders:
# Set up the appropriate options for the pandoc command
inputOptions = chapters
generalOptions = ["-N", "--smart", "--no-tex-ligatures", "--toc", "--standalone",
"--preserve-tabs", "-V documentclass=scrbook", "-V papersize=a4", "-V links-as-note", "-S"]
latexOptions = ["--latex-engine=" + latexEngine]
outputOptions = ["--output={0}".format(pdfBookPath)]
pandocCommand = ["pandoc"] + outputOptions + \
inputOptions + generalOptions + latexOptions
# Print out of the chapters being built and the flags being used
print "Generating {0} from:".format(pdfBookPath)
for chapter in inputOptions:
print "\t{0}".format(chapter)
print "Using the following flags:"
for flag in generalOptions + latexOptions:
print "\t{0}".format(flag)
# For debugging purposes, it's a good idea to generate the .tex. Errors
# printed out through pandoc aren't as useful as those printed
# directly from trying to build a PDF in TeXworks.
texOutputOptions = ["--output={0}".format(texBookPath)]
texPandocCommand = ["pandoc"] + texOutputOptions + \
inputOptions + generalOptions + latexOptions
returnCode = subprocess.call(texPandocCommand)
if returnCode == 0:
print "Successful building of {0}".format(texBookPath)
else:
print "Error in building of {0}".format(texBookPath)
# Call pandoc
returnCode = subprocess.call(pandocCommand)
if returnCode == 0:
print "Successful building of {0}".format(pdfBookPath)
else:
print "Error in building of {0}".format(pdfBookPath)
generalOptions = ["-N", "--toc", "--standalone",
"--preserve-tabs", "-V documentclass=scrbook",
"-V papersize=a4", "-V links-as-note"]
latexOptions = ["--pdf-engine=" + latexEngine]
for outputFormat in args.format:
bookPath = os.path.join(outputPath, "book.{0}".format(outputFormat))
formatOutputOptions = []
if outputFormat == 'epub':
formatOutputOptions = ["--epub-metadata=epub/metadata.xml",
"--epub-cover-image=epub/cover.png"]
outputOptions = ["--output={0}".format(bookPath)] + formatOutputOptions
pandocCommand = ["pandoc"] + inputOptions + outputOptions \
+ generalOptions + latexOptions
# Print out of the chapters being built and the flags being used
print "Generating {0} from:".format(bookPath)
for chapter in inputOptions:
print "\t{0}".format(chapter)
print "Using the following flags:"
for flag in outputOptions + generalOptions + latexOptions:
print "\t{0}".format(flag)
returnCode = subprocess.call(pandocCommand)
if returnCode == 0:
print "Successful building of {0}".format(bookPath)
else:
print "Error in building of {0}".format(bookPath)

@ -1,3 +1,3 @@
<div class="toc-header">
<p> <a href="?lan=jp">日本</a> - <a href="?lan=ch">中文版</a> - <a href="?lan=kr">한국어</a> - <a href="?lan=es">Español</a> - <a href="?lan=fr">Français</a> - <a href="?lan=it">Italiano</a> - <a href="?lan=de">Deutsch</a> - <a href="?lan=ru">Русский</a> - <a href=".">English</a></p>
<p> <a href="?lan=jp">日本</a> - <a href="?lan=ch">中文版</a> - <a href="?lan=kr">한국어</a> - <a href="?lan=es">Español</a> - <a href="?lan=pt">Portugues</a> - <a href="?lan=fr">Français</a> - <a href="?lan=it">Italiano</a> - <a href="?lan=de">Deutsch</a> - <a href="?lan=ru">Русский</a> - <a href=".">English</a></p>
</div>

Loading…
Cancel
Save