Campo de Fluxo - Experimentos em Programação Criativa - 6
Essa é mais uma tentativa de reproduzir uma imagem utilizando computação criativa, puramente para aprender coisas novas e passar o tempo. Esses artigos são principalmente criados como uma forma de catalogar o processo de implementação para referencia futura quando eu estiver desenvolvendo novas coisas.
Inspiração
A imagem que tentei replicar através de código desta vez é a seguinte:
E o meu resultado é o seguinte:
Implementação
Usarei novamento o editor do p5 para essa implementação.
Passo 1
Seguindo a mesma onde do artigo anterior, utilizei como base o código do Daniel Shiffman ensinado neste vídeo. No vídeo, um algoritmo para flow fields é ensinado, e essa é a principal parte necessária para o resultado final.
Seguindo o tutorial, conseguimos o seguinte código como base para o nosso projeto:
1 | const inc = 0.02 |
Retornando esse resultado
Passo 2
Na sequência podemos adicionar as cores e ajustar um pouco as linhas.
Começando pelas cores, podemos adicionar cores aleatórias para as linhas com base em uma lista de cores pré-selecionadas, e atualizar o background
1 | const colors = ['#ff0026', '#ff3400', '#ea3d96', '#7a62a4', '#ffea00', '#98398f', '#839db2', '#0ead00', '#578400'] |
Podemos também alterar a função que desenha a linha para adicionar algumas colas e um pouco de aleatoriedade em quando as linhas devem ou não aparecer
1 | function draw() { |
Passo 3
Agora, vamos adicionar uma máscara para que o flow field apareça apenas dentro de um círculo, e não on canvas inteiro.
O p5.js não possui nenhuma função específica para isso, mas como o código é executado em um canvas HTML, podemos utilizar a própria função dele para isso. Essa discussão nas issues do p5.js explica melhor como isso pode ser usado.
No nosso código, podemos adicionar da seguinte forma:
1 | function draw() { |
Obtendo esse resultado:
Passo 4
O último passo é adicionar uma granularidade para a tela, assim como na imagem original.
Para isso, trapaceei pedindo ao ChatGPT para gerar um código que “granule” o canvas. O resultado foi esse:
1 | function draw() { |
Próximos passos
Algumas ideias para avançar mais nesse projeto seriam brincar com a função de drawLine para chegar mais próximo do resultado original, ou tentar encontrar uma paleta de cores mais semelhantes.
Código completo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71const inc = 0.02
const scl = 10
let cols, rows
const colors = ['#ff0026', '#ff3400', '#ea3d96', '#7a62a4', '#ffea00', '#98398f', '#839db2', '#0ead00', '#578400']
function setup() {
createCanvas(600, 600)
cols = floor(width / scl)
rows = floor(height / scl)
background('#ffd000')
noLoop()
}
function draw() {
noStroke()
// https://github.com/processing/p5.js/issues/3998#issuecomment-670270414
drawingContext.save()
fill('#bfc187')
circle(width / 2, height / 2, height / 1.5)
drawingContext.clip()
// https://thecodingtrain.com/challenges/24-perlin-noise-flow-field
let yoff = 0
for (let y = 0; y < rows; y++) {
let xoff = 0
for (let x = 0; x < cols; x++) {
const index = x + y * cols
const angle = noise(xoff, yoff) * TWO_PI * 4
const v = p5.Vector.fromAngle(angle)
xoff += inc
const c = colors[int(random(0, colors.length))]
stroke(c)
fill(c)
strokeWeight(2)
push();
translate(x * scl, y * scl)
rotate(v.heading())
drawLine(scl)
pop()
}
yoff += inc
}
applyGrainyFilter()
}
function drawLine(size) {
if (random() < 0.9) {
line(0, 0, size, 0)
}
if (random() < 0.7) {
circle(0, 0, 2)
}
}
function applyGrainyFilter() {
loadPixels();
const length = 20
for (let i = 0; i < pixels.length; i += 4) {
// Add random noise to the red, green, and blue channels
pixels[i] += random(-length, length);
pixels[i + 1] += random(-length, length);
pixels[i + 2] += random(-length, length);
}
updatePixels();
}