commit
784114f140
@ -0,0 +1,190 @@
|
||||
![](dragonfly.jpg)
|
||||
|
||||
## Cellular Noise (Ruído Celular)
|
||||
|
||||
Em 1996, dezesseis anos após o Noise original de Perlin e cinco anos antes de seu Noise Simplex, [Steven Worley escreveu um artigo chamado “A Cellular Texture Basis Function” (Uma Função de Base de Textura Celular)](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Neste, ele descreve uma técnica procedimental de texturizar amplamente usada pela comunidade gráfica.
|
||||
|
||||
Para entender os princípios por trás disto, nós precisamos começar a pensar em termos de **iterações**. Provavelmente, você sabe o que isso significa: sim, começar a usar laços de repetição ```for```. Há apenas uma questão com laços de repetição ```for``` em GLSL: o número de vezes que estamos verificando deve ser uma constante (```const```). Logo, sem laços dinâmicos - o número de iterações deve ser fixo.
|
||||
|
||||
Vamos dar uma olhada em um exemplo.
|
||||
|
||||
### Pontos para um campo de distância
|
||||
|
||||
Ruídos celulares são baseados em campos de distância, a distância para o ponto mais próximo de um conjunto de pontos. Vamos dizer que nós queremos criar um campo de distância de 4 pontos. O que nós devemos fazer? Bem, **para cada píxel, nós queremos calcular a distância para o ponto mais próximo**. Que significa que nós precisamos iterar por todos os pontos, computar suas distâncias para o píxel atual e armazenar o valor para o mais próximo.
|
||||
|
||||
```glsl
|
||||
float min_dist = 100.; // A variable to store the closest distance to a point
|
||||
|
||||
min_dist = min(min_dist, distance(st, point_a));
|
||||
min_dist = min(min_dist, distance(st, point_b));
|
||||
min_dist = min(min_dist, distance(st, point_c));
|
||||
min_dist = min(min_dist, distance(st, point_d));
|
||||
```
|
||||
|
||||
![](cell-00.png)
|
||||
|
||||
Isso não é muito elegante, mas resolve. Agora, vamos reimplementá-lo usando um array e um laço ```for```.
|
||||
|
||||
```glsl
|
||||
float m_dist = 100.; // minimum distance
|
||||
for (int i = 0; i < TOTAL_POINTS; i++) {
|
||||
float dist = distance(st, points[i]);
|
||||
m_dist = min(m_dist, dist);
|
||||
}
|
||||
```
|
||||
|
||||
Veja como nós usamos o laço ```for``` para iterar pelo array de pontos e encontrar a menor distância usando uma função [```min()```](../glossary/?search=min). Aqui está uma breve implementação funcional desta ideia:
|
||||
|
||||
<div class="codeAndCanvas" data="cellnoise-00.frag"></div>
|
||||
|
||||
No código acima, um ou mais pontos estão atribuídos à posição do mouse. Interaja com ele para pegar uma ideia mais intuitiva de como o código se comporta. Então, responda:
|
||||
|
||||
- Como você pode animar o resto dos pontos?
|
||||
- Depois de ler [o capítulo sobre formas](../07/), imagine formas interessantes de usar este campo de distância!
|
||||
-E se você quiser adicionar mais pontos ao campo de distância? E se nós quisermos dinamicamente adicionar/subtrair pontos?
|
||||
|
||||
### Tiles e Iteração
|
||||
|
||||
Você provavelmente percebeu que laços ```for``` e *arrays* não se dão bem com GLSL. Como mencionamos antes, laços não aceitam limites dinâmicos em sua condição de saída. Além disso, iterar por muitas instâncias, reduz a performance do shader significativamente. O que significa que nós não podemos usar essa abordagem diretamente para grandes quantidades de pontos. Nós precisamos encontrar outra estratégia, uma que tira vantagem sobre o arquitetura de processamento paralelo da GPU.
|
||||
|
||||
![](cell-01.png)
|
||||
|
||||
Uma forma de abordar este problema é dividindo o espaço em tiles. Cada píxel não precisa checar a distância de cada ponto, certo? Considerando o fato de cada píxel rodar em sua própria thread, nós podemos subdividir o espaço em células, cada uma com um único ponto para observar. Também, para evitar artefatos nas arestas entre as células, nós precisamos verificar as distâncias para os pontos das células vizinhas. Esta é a genial ideia do [artigo de Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). No final, cada píxel precisa verificar apenas nove posições: o ponto da própria célula e os pontos das 8 células ao seu redor. Nós já subdividimos o espaço em células no capítulo sobre [padrões], (../09/), [aleatório](../10/) e [noise](../11/), então você provavelmente já está familiarizado com essa técnica.
|
||||
|
||||
```glsl
|
||||
// Scale
|
||||
st *= 3.;
|
||||
|
||||
// Tile the space
|
||||
vec2 i_st = floor(st);
|
||||
vec2 f_st = fract(st);
|
||||
```
|
||||
|
||||
Então, qual é o plano? Nós usaremos as coordenadas do tile (armazenadas na coordenada inteira ```i_st```) para construirmos uma posição aleatória de um ponto. A função ```random2f``` que nós usaremos recebe um ```vec2``` e nos retorna um ```vec2``` com uma posição aleatória. Então, para cada tile, nós teremos um ponto respectivo em uma posição aleatória dentro do tile.
|
||||
|
||||
```glsl
|
||||
vec2 point = random2(i_st);
|
||||
```
|
||||
|
||||
Cada píxel dentro do tile (armazenado em coordenadas float, ```f_st```) verificará sua distância para um ponto aleatório.
|
||||
|
||||
```glsl
|
||||
vec2 diff = point - f_st;
|
||||
float dist = length(diff);
|
||||
```
|
||||
|
||||
O resultado se parecerá com a seguinte imagem:
|
||||
|
||||
<a href="../edit.php#12/cellnoise-01.frag"><img src="cellnoise.png" width="520px" height="200px"></img></a>
|
||||
|
||||
Ainda precisamos verificar a distância dos pontos nos tiles ao redor, não apenas o atual. Para isso, nós precisamos **iterar** por seus tiles vizinhos. Não todos os tiles, apenas os que estão imediatamente ao redor do atual. Que compreende do tile ```-1``` (esquerda) a ```1``` (direita) no eixo ```x``` e ```-1```(inferior) e ```1``` (superior) no eixo ```y```. Podemos iterar em uma região 3x3 de 9 tiles através de um laço ```for``` duplo como esse:
|
||||
|
||||
```glsl
|
||||
for (int y= -1; y <= 1; y++) {
|
||||
for (int x= -1; x <= 1; x++) {
|
||||
// Neighbor place in the grid
|
||||
vec2 neighbor = vec2(float(x),float(y));
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
![](cell-02.png)
|
||||
|
||||
Agora, nós podemos estimar a distância dos pontos para cada um dos vizinhos em nosso laço ```for``` duplo, ao adicionar o deslocamento do tile vizinho às coordenadas do tile atual.
|
||||
|
||||
```glsl
|
||||
...
|
||||
// Random position from current + neighbor place in the grid
|
||||
vec2 point = random2(i_st + neighbor);
|
||||
...
|
||||
```
|
||||
|
||||
O resto é calcular a distância daquele ponto e armazenar a menor em uma variável chamada ```m_dist``` (para distância mínima).
|
||||
|
||||
```glsl
|
||||
...
|
||||
vec2 diff = neighbor + point - f_st;
|
||||
|
||||
// Distance to the point
|
||||
float dist = length(diff);
|
||||
|
||||
// Keep the closer distance
|
||||
m_dist = min(m_dist, dist);
|
||||
...
|
||||
```
|
||||
|
||||
O código acima foi inspirado por [este artigo de Inigo Quilez](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm) onde ele diz:
|
||||
|
||||
*"... Pode valer a pena perceber que existe um truque excelente no código acima. A maioria das implementações por aí sofrem com problemas de precisão, porque eles geram seus pontos aleatórios no espaço "domínio" (como espaço "mundo" ou espaço "objeto"), que podem ser longe da origem. Pode-se resolver este problema ao aumentar a precisão dos dados, ou sendo um pouco esperto. Minha implementação não gera os pontos em um espaço "domínio", mas em espaço "célula": uma vez que as partes inteira e fracionária do ponto desejado são extraídas e a célula em que estamos trabalhando, identificada, todos nós nos importamos com o que acontece ao redor desta célula, assim nós podemos nos livrar de todas as partes inteiras de uma vez, nós economizando bits de precisão. De fato, em uma implementação de voronoi usual, as partes inteiras das coordenadas do ponto simplesmente se cancelam quando o aleatório pelos pontos da respectiva célula são subtraídos do ponto em questão. Em minha implementação acima, nós nem ao menos deixamos esse cancelamento acontecer, pois estamos movendo todos os cálculos para o espaço "célula". Estudo truque também permite que lidemos com os casos nos quais queremos usar voronoi para desenhar um planeta inteiro - poderíamos simplesmente substituir a entra para ser precisão double, realizar os cálculos de floor() e fract(), e então mudarmos para ponto-flutuante para os próximos cálculos sem pagarmos o custo de trocar toda implementação para precisão double. Naturalmente, alguns truques se aplicam ao ruído Perlin (ainda que eu não tenha visto isto documentado ou implementado)."*
|
||||
|
||||
Recapitulando: nós subdividimos o espaço em tiles; cada píxel calculará a distância do ponto do seu próprio tile e dos 8 ao seu redor; armazenará a menor distância. O resultado será um campo de distância que se parece com o exemplo a seguir:
|
||||
|
||||
<div class="codeAndCanvas" data="cellnoise-02.frag"></div>
|
||||
|
||||
Vá além ao:
|
||||
|
||||
- Transformar a escala no espaço para diferentes valores.
|
||||
- Você consegue pensar em outras formas de animar os pontos?
|
||||
- E se quisermos calcular um ponto extra com a posição do mouse?
|
||||
- Quais são as outras formas de construir este campo de distância, você consegue pensar em uma além de ```m_dist = min(m_dist, dist);```?
|
||||
- Que padrões interessantes você pode criar com este campo de distância?
|
||||
|
||||
O algoritmo pode também ser interpretado pela perspectiva do ponto e não dos píxeis. Neste caso, ele pode ser descrito como: cada ponto cresce até que ele encontre a área de crescimento de outro ponto. Isso reflete algumas leis de crescimento na natureza. Formas de vida são moldadas por essa tensão entre a força interior de crescer e se expandir e as limitações das forças externas. O clássico algoritmo que simula este comportamento foi nomeado em homenagem a [Georgy Voronoi](https://en.wikipedia.org/wiki/Georgy_Voronoy).
|
||||
|
||||
![](monokot_root.jpg)
|
||||
|
||||
### O Algoritmo de Vonoroi
|
||||
|
||||
Construindo diagramas a partir de ruído celular é menos complicado do que parece. Nós apenas precisamos *manter* algumas informações extras sobre o ponto que é o mais próximo de cada píxel. Para isso, nós vamos usar um ```vec2``` chamado ```m_point```. Ao armazenar a direção do vetor até o centro do ponto mais próximo, ao invés de apenas a distância, nós "manteremos" um "único" identificador para aquele ponto.
|
||||
|
||||
```glsl
|
||||
...
|
||||
if( dist < m_dist ) {
|
||||
m_dist = dist;
|
||||
m_point = point;
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
Veja que no código a seguir que não estamos mais usando ```min``` para calcular a distância do ponto mais próximo, mas um ```if```. Por quê? Porque nós queremos fazer algo toda a vez que um ponto mais próximo aparecer, armazenar sua posição (linhas 32 a 37).
|
||||
|
||||
<div class="codeAndCanvas" data="vorono-00.frag"></div>
|
||||
|
||||
Veja como a cor do movimento celular (vinculada à posição do mouse) muda sua cor de acordo com a sua posição. Isso acontece porque a cor é atribuída usando o valor (posição) do ponto mais próximo.
|
||||
|
||||
Como nós fizemos antes, agora é hora de ir além, mudar para a abordagem do artigo de Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Tente implementá-lo sozinho. Você pode usar a ajuda dos seguintes exemplos clicando neles. Veja que a abordagem original de Steven Worley usa um número variável de pontos para cada tile, mais de um em sua maioria. Em sua implementação em C, isso é usado para acelerar o laço ao fazer uma saída antecipada. Laços em GLSL não permitem um número variavel de iterações, então você provavelmente vai querer manter um ponto por tile.
|
||||
|
||||
<a href="../edit.php#12/vorono-01.frag"><canvas id="custom" class="canvas" data-fragment-url="vorono-01.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
Depois que você pensar neste algoritmo, pense em seus vários usos interessantes e criativos.
|
||||
|
||||
![Extended Voronoi - Leo Solaas (2011)](solas.png)
|
||||
|
||||
![Cloud Cities - Tomás Saraceno (2011)](saraceno.jpg)
|
||||
|
||||
![Accretion Disc Series - Clint Fulkerson](accretion.jpg)
|
||||
|
||||
![Vonoroi Puzzle - Reza Ali (2015)](reza.png)
|
||||
|
||||
### Melhorando Voronoi
|
||||
|
||||
Em 2011, [Stefan Gustavson otimizou o algoritmo de Steven Worley para GPU](http://webstaff.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf) ao iterar por uma matriz de 2x2 ao invés de 3x3. Isso reduz a quantidade de trabalho significativamente, mas pode criar artefatos em forma de descontinuidades nas arestas entre os tiles. Dê uma olhada no seguinte exemplo.
|
||||
|
||||
<div class="glslGallery" data="12/2d-cnoise-2x2,12/2d-cnoise-2x2x2,12/2d-cnoise,12/3d-cnoise" data-properties="clickRun:editor,openFrameIcon:false"></div>
|
||||
|
||||
Mais tarde em 2012 [Inigo Quilez escreveu um artigo sobre como criar bordas mais precisas em Voronoi](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm).
|
||||
|
||||
<a href="../edit.php#12/2d-voronoi.frag"><img src="2d-voronoi.gif" width="520px" height="200px"></img></a>
|
||||
|
||||
Os experimentos de Inigo com Voronoi não pararam aí. Em 2014, ele escreveu um excelente artigo sobre o que ele chama [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm), uma função que permite uma mesclagem gradual entre o ruído comum e voronoi. Em suas palavras:
|
||||
|
||||
*"Apesar de sua similaridade, o fato é que a forma que a grade é usada em ambos padrões é diferente. O ruído interpola valores aleatórios (como ruído de valor) ou gradiente (como em ruído de gradiente), enquanto Voronoi calcula a distância de um respectivo ponto. Agora, a interpolação bilinear e a verificação da menor distância são duas operações diferentes, ou.... elas são? Poderiam elas serem combinadas em uma métrica mais geral? Se sim, então tanto Ruído como Voronoi podem ser vistos como casos particulares de um gerador de padrão baseado em grade mais geral?"*
|
||||
|
||||
<a href="../edit.php#12/2d-voronoise.frag"><canvas id="custom" class="canvas" data-fragment-url="2d-voronoise.frag" width="520px" height="200px"></canvas></a>
|
||||
|
||||
Agora, é hora de você dar uma olhada nas coisas, se inspire pela natureza e encontre a sua própria forma de usar esta técnica!
|
||||
|
||||
![Deyrolle glass film - 1831](DeyrolleFilm.png)
|
||||
|
||||
<div class="glslGallery" data="12/metaballs,12/stippling,12/cell,12/tissue,12/cracks,160504143842" data-properties="clickRun:editor,openFrameIcon:false"></div>
|
@ -0,0 +1,112 @@
|
||||
![Due East over Shadequarter Mountain - Matthew Rangel (2005) ](rangel.jpg)
|
||||
|
||||
## Movimento Browniano Fracionário
|
||||
|
||||
O ruído pode ter um significado diferente para diferentes pessoas. Músicos pensarão em sons irritantes, comunicadores como interferência e astrofísicos como radiação em micro-ondas cósmicas. Estes conceitos nos trazem às explicações físicas por trás da aleatoriedade do mundo em nossa volta. Entretanto, vamos começar por algo mais fundamental e simples: ondas e suas propriedades. Uma onda é uma flutuação de alguma propriedade pelo tempo. Ondas de som são flutuações sobre a pressão do ar, ondas eletromagnéticas são flutuações em campos elétricos e magnéticos. Duas importantes características de onda são sua amplitude e sua frequência. A equação para uma simples onda linear (unidimensional) tem este aspecto.
|
||||
|
||||
<div class="simpleFunction" data="
|
||||
float amplitude = 1.;
|
||||
float frequency = 1.;
|
||||
y = amplitude * sin(x * frequency);
|
||||
"></div>
|
||||
|
||||
* Experimente alterar os valores de frequência e amplitude para entender como eles se comportam.
|
||||
* Usando modelagem de funções, tente alterar a amplitude ao longo do tempo.
|
||||
* Usando modelagem de funções, tente alterar a frequência ao longo do tempo.
|
||||
|
||||
Ao fazer estes últimos exercícios, você conseguiu "modular" uma onda de seno, e você acabou de criar ondas AM (amplitude modulada) e FM (frequência modulada). Parabéns!
|
||||
|
||||
Outra interessante propriedade das ondas é a habilidade de se somarem, formalmente chamada de superposição. Comente/descomente e ajuste as linhas a seguir. Preste atenção em como sua aparência em geral se altera conforme nós adicionamos ondas de diferentes amplitudes e frequências juntas.
|
||||
|
||||
<div class="simpleFunction" data="
|
||||
float amplitude = 1.;
|
||||
float frequency = 1.;
|
||||
y = sin(x * frequency);
|
||||
float t = 0.01*(-u_time*130.0);
|
||||
y += sin(x*frequency*2.1 + t)*4.5;
|
||||
y += sin(x*frequency*1.72 + t*1.121)*4.0;
|
||||
y += sin(x*frequency*2.221 + t*0.437)*5.0;
|
||||
y += sin(x*frequency*3.1122+ t*4.269)*2.5;
|
||||
y *= amplitude*0.06;
|
||||
"></div>
|
||||
|
||||
|
||||
* Experimente alterar a frequência e amplitude das ondas adicionais.
|
||||
* É possível fazer com que duas ondas se cancelem?
|
||||
* É possível adicionar ondas de uma forma que elas possam se amplificar?
|
||||
|
||||
Em música, cada nota é associada com uma frequência específica. As frequências para estas notas seguem um padrão que chamamos de escala, onde dobrando ou diminuindo pela metade, a frequência corresponde a um salto de uma oitava.
|
||||
|
||||
Agora, vamos usar o ruído Perlin em vez de uma onda de seno! Ruído Perlin em sua forma básica se assemelha muito a uma onda de seno. Sua amplitude e frequência variam, mas a amplitude se mantém razoavelmente consistente, e a frequência é restrita a um curto intervalo ao redor da frequência central. Não é uniforme como uma onda de seno, no entanto, e é mais fácil de criar uma aparência de aleatoriedade ao somar diversas versões em diferentes escalas. Também possível criar uma soma de ondas de seno se parecerem com aleatório, mas é preciso muitas ondas diferentes para esconder a sua natureza periódica e regular.
|
||||
|
||||
Ao adicionar diferentes iterações ao ruído (*oitavas*), onde nós sucessivamente incrementamos as frequências em passos regulares (*lacunaridade*) e diminuímos a amplitude (*ganho*) do **ruído**, nós podemos obter uma granularidade no ruídos e ganhando detalhes mais finos. Esta técnica é chamada "Movimento browniano fracionário" (*fBM*), ou simplesmente "ruído fractal", sua forma mais simples pode ser criada com o seguinte código:
|
||||
|
||||
<div class="simpleFunction" data="// Properties
|
||||
const int octaves = 1;
|
||||
float lacunarity = 2.0;
|
||||
float gain = 0.5;
|
||||
//
|
||||
// Initial values
|
||||
float amplitude = 0.5;
|
||||
float frequency = 1.;
|
||||
//
|
||||
// Loop of octaves
|
||||
for (int i = 0; i < octaves; i++) {
|
||||
	y += amplitude * noise(frequency*x);
|
||||
	frequency *= lacunarity;
|
||||
	amplitude *= gain;
|
||||
}"></div>
|
||||
|
||||
* Progressivamente mude o número de oitavas para iterar de 1 para 2, 4, 8 e 10. Veja o que acontece.
|
||||
* Quando você ter mais do que 4 oitavas, tente mudar o valor de lacunaridade.
|
||||
* Também, com mais de 4 oitavas, mude o valor gain(ganho) e veja o que acontece.
|
||||
|
||||
Veja como cada oitava adicional, a curva se parece mais detalhada. Também veja que a auto-similaridade enquanto mais oitavas são adicionadas. Se você se aproximar da curva, uma parte pequena se parecerá com o todo, e cada seção se parece mais ou menos igual a qualquer outra seção. Esta é uma importante propriedade dos fractais matemáticos, e nós estamos simulando esta propriedade em nosso loop. Nós não estamos criando um *verdadeiro* fractal, porque nós pararíamos nossa simulação depois de algumas iterações, mas, teoricamente falando, nós obteríamos um verdadeiro fractal se nós permitíssemos que o laço continuasse para sempre adicionando um infinito número de ruídos componentes. Em computação gráfica, nós sempre temos um limite do que nós podemos determinar, por exemplo, quando um objeto se torna menor que um píxel, então não há necessidade de criar somas infinitas para criar a aparência de um fractal. As vezes, muitos termos podem ser necessários, mas nunca um número infinito.
|
||||
|
||||
O código a seguir é um exemplo de como fBm pode ser implementado em duas dimensões para criar um padrão parecido com um fractal:
|
||||
|
||||
<div class='codeAndCanvas' data='2d-fbm.frag'></div>
|
||||
|
||||
* Reduza o número de oitavas ao trocar os valores na linha 37
|
||||
* Modifique a lacunaridade do fBm na linha 47
|
||||
* Experimente mudar o Ganho(gain) na linha 48.
|
||||
|
||||
Esta técnica é regularmente usada na criação de paisagens procedimentais. A auto-similaridade do fBm é perfeita para montanhas, porque o processo de erosão cria montanhas que funcionam de um jeito que produzem esse tipo de auto-similaridade por um largo intervalo de escalas. Se você está interessado nisso, você definitivamente deveria ler [este ótimo artigo por Inigo Quilez sobre ruído avançado](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm).
|
||||
|
||||
![Blackout - Dan Holdsworth (2010)](holdsworth.jpg)
|
||||
|
||||
Usando mais ou menos a mesma técnica, é possível obter outros efeitos como o que é conhecido como **turbulência**. É essencialmente um fBm, mas construída com valores absolutos de um ruído sinalizado para criar vales afiados na função.
|
||||
|
||||
```glsl
|
||||
for (int i = 0; i < OCTAVES; i++) {
|
||||
value += amplitude * abs(snoise(st));
|
||||
st *= 2.;
|
||||
amplitude *= .5;
|
||||
}
|
||||
```
|
||||
|
||||
<a href="../edit.php#13/turbulence.frag"><img src="turbulence-long.png" width="520px" height="200px"></img></a>
|
||||
|
||||
Outro membro desta família de algoritmos é o *cume* (ridge), onde os vales afiados são virados de ponta-cabeça para criar cumes afiados.
|
||||
|
||||
```glsl
|
||||
n = abs(n); // create creases
|
||||
n = offset - n; // invert so creases are at top
|
||||
n = n * n; // sharpen creases
|
||||
```
|
||||
|
||||
<a href="../edit.php#13/ridge.frag"><img src="ridge-long.png" width="520px" height="200px"></img></a>
|
||||
|
||||
Outra variante pode criar variações úteis é multiplicando os componentes do ruído juntos ao invés de somá-los. Também é interessante alterarmos a escala de funções de ruído subsequentes com algo que dependa dos termos anteriores do nosso laço. Quando nós fazemos operações assim, nós estando nos afastando de uma definição estrita de fractal e entrando relativamente em um campo desconhecido de "multifractais". Multifractais não são estritamente matematicamente definidos, mas não significa que que os torna menos úteis em gráficos. De fato, simulações multifractais são muito comuns em comerciais modernos para gerar terrenos. Para ir além, você pode ler o capítulo 16 do livro "Texturing and Modeling: A procedural approach" (Texturizando e Modelando: Uma Abordagem Procedimental) - 3ª edição, por Kenton Musgrave. Infelizmente, este livro está fora de impressão há alguns anos, mas nós ainda podemos encontrá-lo em bibliotecas e em mercados de segunda-mão. (Tem uma versão em PDF da primeira edição disponível para venda online, mas não a compre - É um desperdício de dinheiro. É de 1994, e não contém o tópico de modelagem de terreno da terceira edição).
|
||||
|
||||
## Domain Warping (Empenamento de Domínio)
|
||||
|
||||
[Inigo Quilez escreveu outro artigo fascinante](http://www.iquilezles.org/www/articles/warp/warp.htm) sobre como é possível usarmos o fBm para distorcer um espaço de um fBm. Surpreendente, não é? É como um sonho dentro de um sonho em A Origem (Inception).
|
||||
|
||||
![ f(p) = fbm( p + fbm( p + fbm( p ) ) ) - Inigo Quiles (2002)](quiles.jpg)
|
||||
|
||||
Uma exemplo menos extremo desta técnica está nas seguintes linhas de código, onde o empenamento é usado para produzir estas texturas parecidas com nuvem. Veja como a propriedade de auto-similaridade está presente no resultado.
|
||||
|
||||
<div class='codeAndCanvas' data='clouds.frag'></div>
|
||||
|
||||
Empenar as coordenadas da textura com um ruído pode ser muito útil e divertido, entretanto, diabolicamente difícil de dominar. É uma ferramenta poderosa, mas requer um pouco de experiência pra usá-la bem. Uma ferramenta útil para isso é deslocar as coordenadas com as derivadas (gradiente) do ruído. [Um artigo famoso de Ken Perlin e Fabrice Neyret chamado "flow noise"](http://evasion.imag.fr/Publications/2001/PN01/) é baseado nesta ideia. Algumas implementações modernas do ruído Perlin incluem a variante que calcula tanto a função como seu gradiente analítico. Se o "verdadeiro" gradiente não estiver disponível para nossa função procedimental, você sempre pode calcular as diferenças finitas para se aproximar dele, apesar de ser menos preciso e envolver mais trabalho.
|
@ -1,5 +1,5 @@
|
||||
*[kynd](http://www.kynd.info) Nov 20, 2016*
|
||||
|
||||
Shaders are often used to create realistic surfaces of natural or artificial material such as wood, marble, granite, metal, stone, etc. without using photographs or pre-rendered images. Here are demonstrations of some basic techniques. All the examples are based on anumber of random and noise functions from [Random](http://thebookofshaders.com/10/), [Noise](http://thebookofshaders.com/11/), [Cellular Noise](http://thebookofshaders.com/12/) and [Fractal Brownian Motion](http://thebookofshaders.com/13/) chapters. Once you get the basic ideas, try tweaking and adding more details to make them more realistic, coming up with new textures and optimizing the performance.
|
||||
Shaders are often used to create realistic surfaces of natural or artificial material such as wood, marble, granite, metal, stone, etc. without using photographs or pre-rendered images. Here are demonstrations of some basic techniques. All the examples are based on a number of random and noise functions from [Random](http://thebookofshaders.com/10/), [Noise](http://thebookofshaders.com/11/), [Cellular Noise](http://thebookofshaders.com/12/) and [Fractal Brownian Motion](http://thebookofshaders.com/13/) chapters. Once you get the basic ideas, try tweaking and adding more details to make them more realistic, coming up with new textures and optimizing the performance.
|
||||
|
||||
Note that the terrain examples at the bottom use normal map and lighting which are techniques not yet introduced in this book. In short, what they do is to generate a map of the directions of the surface and shade the pixels accordingly. We will cover these ideas in future chapters. Stay tuned.
|
||||
|
Loading…
Reference in New Issue