Sara Maria Addonato – Generative landscape

/*
OBIETTIVO VISIVO:
Rappresentare un paesaggio montuoso generativo in continua evoluzione durante un ciclo giorno-notte interattivo.
L’obiettivo è creare una scena profonda e suggestiva in cui l’atmosfera del cielo reagisce all’utente e la
natura appare dinamica grazie al movimento costante delle nuvole e al brillio asincrono delle stelle.

SCOMPOSIZIONE LOGICA:

  1. Cielo e Atmosfera: Un gradiente dinamico a tre stadi (Giorno, Tramonto, Notte) che cambia fluidamente
    tramite lerpColor() in base alla posizione Y del mouse. La luminosità è bilanciata per garantire
    sempre la visibilità delle silhouette montuose.
  2. Stratificazione e Profondità (Layering): La scena è organizzata su tre piani di spostamento apparente:
    • Background: Stelle fisse (salvate in array) che appaiono solo con l’oscurità.
    • Mid-ground: Catene montuose distanti e nuvole organiche bianche in movimento orizzontale.
    • Foreground: Montagne imponenti con volumi definiti.
  3. Montagne (Funzione Custom): Ho creato la funzione “disegnaMontagna(x, yBase, w, h, col)”.
    Per superare l’effetto “piatto”, la funzione disegna due triangoli affiancati con tonalità diverse,
    simulando una luce radente che conferisce volume 3D agli elementi.
  4. Nuvole e Stelle:
    • Le nuvole sono gestite tramite un array di oggetti e si muovono con velocità diverse.
    • Le stelle utilizzano l’operatore modulo (%) per creare un effetto “twinkling” casuale.
    USO AI:
    Ho utilizzato Gemini come “Pair Programmer” per ottimizzare la gestione della memoria tramite array
    e per il calcolo matematico della luce sulle facce delle montagne.
    Il prompt chiave è stato: “Come posso modificare una funzione che disegna triangoli in p5.js per
    aggiungere un’ombra su un lato e dare profondità al paesaggio?”
    Ho imparato così a manipolare i valori RGB del colore passato come parametro per creare varianti tonali.
    */

let stelleX = [];
let stelleY = [];
let numStelle = 150;

let nuvole = [];
let numNuvole = 6;

function setup() {
createCanvas(800, 600);

// Setup stelle
for (let i = 0; i < numStelle; i++) {
stelleX.push(random(width));
stelleY.push(random(height / 2));
}

// Setup nuvole (campitura piena)
for (let i = 0; i < numNuvole; i++) {
nuvole.push({
x: random(width),
y: random(40, 180),
v: random(0.2, 0.6),
s: random(0.5, 0.9)
});
}
}

function draw() {
// 1. CIELO DINAMICO (Gradazione graduale)
let val = map(mouseY, 0, height, 0, 1, true);
let colSopra, colSotto;

if (val < 0.5) {
let inter = map(val, 0, 0.5, 0, 1);
colSopra = lerpColor(color(135, 206, 235), color(100, 70, 160), inter);
colSotto = lerpColor(color(255, 255, 255), color(255, 160, 80), inter);
} else {
let inter = map(val, 0.5, 1, 0, 1);
// Il colore finale (Notte) non è nero puro per mantenere visibili le montagne
colSopra = lerpColor(color(100, 70, 160), color(35, 30, 70), inter);
colSotto = lerpColor(color(255, 160, 80), color(70, 45, 100), inter);
}

for (let i = 0; i <= height; i++) {
let inter = map(i, 0, height, 0, 1);
stroke(lerpColor(colSopra, colSotto, inter));
line(0, i, width, i);
}

// 2. STELLE
let starAlpha = map(val, 0.6, 1, 0, 255, true);
stroke(255, starAlpha);
for (let i = 0; i < numStelle; i++) {
strokeWeight(random(1, 2));
point(stelleX[i], stelleY[i]);
}

// 3. SOLE / LUNA
let sunY = map(mouseY, 0, height, 80, height + 50);
noStroke();
fill(255, 255, 200, 230);
circle(width / 2, sunY, 70);

// 4. NUVOLE (Campitura piena)
for (let n of nuvole) {
disegnaNuvola(n.x, n.y, n.s);
n.x += n.v;
if (n.x > width + 100) n.x = -150;
}

// 5. MONTAGNE CON PROFONDITÀ (Tre livelli di parallasse)
// Livello Lontano (Chiaro e piccolo)
for (let x = -50; x <= width + 50; x += 180) {
disegnaMontagna(x, height, 350, 180, color(85, 80, 130));
}

// Livello Medio
for (let x = -100; x <= width + 100; x += 250) {
disegnaMontagna(x + 40, height, 500, 280, color(55, 45, 95));
}

// Livello Vicino (Scuro e grande)
for (let x = -200; x <= width + 200; x += 400) {
disegnaMontagna(x, height, 750, 400, color(30, 20, 55));
}
}

// — FUNZIONI CUSTOM —

// Funzione montagna: disegna due facce per il volume
function disegnaMontagna(x, yBase, w, h, col) {
noStroke();

// Faccia Sinistra (Ombra – leggermente più scura)
fill(red(col)0.8, green(col)0.8, blue(col)*0.8);
beginShape();
vertex(x – w / 2, yBase);
vertex(x, yBase – h);
vertex(x, yBase);
endShape(CLOSE);

// Faccia Destra (Luce – colore originale)
fill(col);
beginShape();
vertex(x, yBase – h);
vertex(x + w / 2, yBase);
vertex(x, yBase);
endShape(CLOSE);
}

function disegnaNuvola(x, y, s) {
push();
translate(x, y);
scale(s);
noStroke();
fill(255); // Bianco solido
ellipse(0, 0, 70, 40);
ellipse(20, -10, 60, 45);
ellipse(-20, -5, 50, 35);
ellipse(40, 5, 50, 30);
pop();
}

✨ Con il movimento del mouse in senso verticale, si vede il cambiamento del cielo, dall’alba al tramonto.

Commenti

Lascia un commento