Desenhar 101: Primitivas Gráficas 2D

O primeiro e mais direto objetivo de aprendizagem no Processing é aprender a desenhar. Não porque o vamos fazer regularmente, muito pelo contrário. No Processing, o uso de gráficos é, normalmente, simples. Quando queremos imagens ou vetores complexos podemos sempre importar.

Sistema de coordenadas cartesianas (como aprendemos na escola) e o sistema de coordenadas do canvas do Processing. Repare quem o x: 0 e y: 0 são no canto superior esquerdo e não no fundo.

[See processing.org tutorials]

Mas, em primeiro lugar, é preciso aprender a manipular o sistema de coordenadas cartesianas do ecrã. O Processing trabalha com uma metáfora de “sketchbook” (caderno de esboços) onde desenhamos. O “0 x 0” (a origem) da página está no canto superior esquerdo. Aumenta para a direita (x) e para baixo (y).

A forma mais rápida de colocar isto em ação é desenhar primitivas gráficas 2D.

O primeiro desafio consiste em desenhar uma forma ou desenho apenas com estas primitivas. Há algumas simples (retângulos e elipses). Há outras mais complexas (curvas e béziers).

A partir do conjunto de primitivas gráficas, que tal desenhar um robô ou personagem favorito? Uma forma simples de colocar isto em ação é escolher o vosso robô favorito de filme de imagem real ou de animação e tentar desenha-lo. Ou então… escolher a vossa mini-figura Lego favorita!

Stormtrooper Lego mini figurine. Qualquer coisa em Lego é perfeito para reproduzir em Processing 😉

Depois é só tentar decompor a forma e simples instruções geométricas e atribuir cores de preenchimento e de contorno.

Ponto primeiro. Explorar as propriedades do IDE do Processing. Embora ainda seja um pouco prematuro — pois nesta fase ainda não estamos a usar o Processing em modo (completo) dinâmico — há algumas funções a saber.

Environment

Estas são mais específicas e vão ser úteis em breve

As restantes, vão ser úteis no segundo módulo (201, 202, …)

Depois de configurar a janela é importante começar a desenhar coisas. Aqui todas as primitivas gráficas são relevantes e importam explorar

2D Primitives

E, porque desenhar sempre com os gráficos pré-definidos (a branco e preto) não tem muita piada, é preciso configurar as propriedades e atributos (visuais) do desenho — configurar sempre a cor de preenchimento e contorno antes de desenhar formas.

Conseguem desenhar uma personagem de ilustração infantil?

Baseado na Miffy do Dick Bruna

(Color) Setting

Obrigatório começar com

O Background serve para configurar a cor de fundo da aplicação.

E depois explorar a forma restante de atribuir cores às formas desenhadas

Igualmente importante são os atributos formais (do contorno ou linhas)

Attributes

Depois de dominados os gráficos simples, é “obrigatório” a exploração de formas complexas (polígonos simples)

Vertex

Assim que estiver dominado, avançar para

Mais difícil de controlar, mas muito importante são as curvas vetoriais em Béziers. Este é o “derradeiro” nível de controlo gráfico e do sistema cartesiano de coordenadas. Dominem estas e tudo o resto que desenharem vai ser fácil.

Curves

Os beziers são uma das primitivas mais complexas de utilizar. Porquê—perguntam vocês?. Porque sim.

Um pouco menos intuitivo mas mais fácil de digerir são as curvas

O objetivo do desenho de primitivas é — precisamente — dar forma à programação que se quer visual. Um desafio comum que aparece nos manuais como o que usamos em LSI. E, por isso, aqui fica o desafio: desenhar um robô apenas com primitivas gráficas simples (ou mais complexas, como as shapes).

Sketch final da Miffy (2020)
// PAmado 2021-02-18
// Miffy from Dick Bruna

// Configurar a aplicação
size(500, 500);

// Cenário
background(200, 0, 0);

// Configurar as propriedades da miffy
// noStroke();
stroke(0);
strokeWeight(20); // hack: double the weight 

fill(255);
rectMode(CENTER);

// Orelhas // Orelha direita (stroked)
rect(180, 175, 70, 150);
ellipse(180, 96, 70, 80);

// Orelha esquerda
rect(320, 175, 70, 150);
ellipse(320, 96, 70, 80); // <-- hack para acertar o contorno… subir um pouco

// restore stroke
stroke(0);
strokeWeight(10);

// Cara
ellipse(250, 300, 300, 200);

// "clean" srossing stroke shapes
noStroke();
rect(180, 175, 70, 150);
ellipse(180, 96, 70, 80);
rect(320, 175, 70, 150);
ellipse(320, 96, 70, 80);

// Olhos
// Olho Direito
fill(0);
ellipse(180, 300, 30, 50);

// Passar a linhas para focinho e olho
noFill();
stroke(0);
strokeWeight(10);

// Olho Esquerdo

arc(320, 310, 40, 40, 5* PI/4, 7 * PI/4);

//arc(320, 260, 40, 40, 1.75 * PI, 2.25 * PI);

// Focinho


line(230, 360, 270, 340);
line(230, 340, 270, 360);

Stormtrooper (2018)
// Stormtrooper v.1 2018-02-12
// PAmado

size(500, 500);

noFill();
noStroke();
rectMode(CENTER);

background(225);
noFill();
noStroke();

// Neck
fill(0);
rect(250, 122, 20, 20, 6);

// Waist
// Pelvis
fill(0);
rect(250, 225, 115, 15);

// Crotch
rect(250, 245, 20, 50);

// Hands
// Wrists (almost pelvis height)
stroke(0);
strokeWeight(18);
line(250-66, 170, 250-76, 195); // right
line(250+66, 170, 250+76, 195); // left

// Clamp
strokeWeight(12);
noFill();
arc(250-85, 218, 33, 33, -3.5, 0.9); // right
arc(250+85, 218, 33, 33, -4.2, 0.3); // left

// Head
noStroke();
fill(255, 200, 0);
rect(250, 90, 68, 52, 8);
rect(250, 83, 32, 52, 8);
// Eyes
fill(0);
ellipse(250-10, 83, 10, 10); // right
ellipse(250+10, 83, 10, 10); // left

// Mouth
noFill();
stroke(0);
strokeWeight(6);
line(250-8, 100, 250+8, 100);

// Body
noStroke();
fill(250);
beginShape();
vertex(250-50, 120); // top left
vertex(250-56, 215);
vertex(250+57, 215);
vertex(250+50, 120); // top right
endShape(CLOSE);
// Abdomins
noFill();
stroke(0);
strokeWeight(2);
beginShape();
vertex(250-46, 200); // top left
vertex(250-28, 175);
vertex(250+28, 175);
vertex(250+46, 200); // top right
endShape(OPEN);

// Arms
noFill();
stroke(250);
strokeWeight(27);
line(250-45, 132, 250-66, 165); // left arm
line(250-66, 165, 250-70, 180); // left forearm
line(250+45, 132, 250+66, 165); // right arm
line(250+66, 165, 250+70, 180); // right forearm

// Elbows (shadows)

// Legs
noStroke();
fill(250);
rect(250-32, 277, 48, 86); // right
rect(250+32, 277, 48, 86); // left

// Knees (lines)
stroke(0);
strokeWeight(2);
line(250-50, 275, 250-15, 275);
beginShape();
vertex(250+15, 275);
vertex(250+24, 265);
vertex(250+43, 265);
vertex(250+52, 275);
endShape(OPEN);

// Feet
noStroke();
fill(240);
rect(250-32, 300, 44, 5); // right
rect(250+32, 300, 44, 5); // left

// Helmet
noStroke();
fill(240); // draw shadows
rect(250, 95, 75, 88, 20); // base shadow (+5 px below)

fill(250);
rect(250, 85, 75, 85, 30); // base
// earpieces
rect(250, 88, 90, 25, 10);
// side breathers
noFill();
strokeWeight(20);

// draw shadows
stroke(240);
line(250-38, 120, 250-20, 135);
line(250+37, 120, 250+20, 135);

stroke(250);
line(250-38, 115, 250-20, 130);
line(250+38, 115, 250+20, 130);

// Face
noStroke();
fill(0);
// Eyes
rect(250, 74, 77, 6); // eyebrows
triangle(250-36, 73, 250-30, 92, 250-5, 78);
triangle(250+35, 75, 250+30, 92, 250+5, 78);
// Mouth
beginShape();
vertex(250-30, 120); // bottom right
vertex(250, 95); // nose
vertex(250+30, 120); 
vertex(250, 110); 

endShape(CLOSE);

// side breathers
ellipse(250-20, 132, 10, 10);
ellipse(250+20, 132, 10, 10);

// middle mouth
beginShape();
vertex(250-5, 125); 
vertex(250+5, 125);  
vertex(250+10, 135); 
vertex(250-10, 135);  
endShape(CLOSE);

Este documento é um artigo em progresso. Atualizado em 2020-02-20, 2021-02-24, 2021-03-08