xxxxxxxxxx
/*
Ouroboros #WCCChallenge "Snake" 250202
https://openprocessing.org/sketch/2529455
#generativeart #creativecoding #p5js
Dear Raph and creative coding community,
Happy new Snake Year!
Inspired by `Ouroboros`, a large public sculpture by Australian
artist Lindy Lee at the National Gallery of Australia forecourt
https://en.wikipedia.org/wiki/Ouroboros
Interesting:
- enable / disable background() in draw();
- enable/disable water in drawBassin()
Issues:
- water is semi transparent, but not showing objects/tiles underwater
Join the Birb's Nest Discord for friendly creative coding community
and future challenges and contributions: https://discord.gg/S8c7qcjw2b
WCCC-Contributions: https://openprocessing.org/curation/78544
*/
const showBg = false;
const showWater = true;
const showTiles = false;
const PALETTES = [
["white"],
["silver", "white"],
["rgb(8,68,8)", "rgb(179,108,22)"],
["rgb(70,38,6)", "rgb(142,112,71)"],
["rgb(179,132,140)", "rgb(108,190,190)"]
];
const SKY_CLRS = ["lightblue", "navy"]
let CLRS, snRadi, maxDia, trees;
function setup() {
createCanvas((S = min(windowWidth, windowHeight)), S, WEBGL);
describe("winding ouroborous over a bassin, inspired by australian sculpture ");
pixelDensity(1);
frameRate(30);
background(lerpColor(color(SKY_CLRS[0]), color(SKY_CLRS[1]), random()));
noStroke();
CLRS = PALETTES[frameCount % PALETTES.length];
S /= 1.2;
snRadi = S / random(2.5, 3.1);
maxDia = snRadi / random(1.1, 2.1);
trees = placeTrees(~~random(5, 7));
}
function draw() {
// background(2, 2, 12);
const skyF = (sin(frameCount/123) + 1) / 2; // 0..1..0 cycling
const skyC = lerpColor(color(SKY_CLRS[0]), color(SKY_CLRS[1]), skyF);
skyC.setAlpha(32);
if (showBg) background(skyC); // nice effect without background
lights();
orbitControl();
spotLight(color(255), createVector(0,-S,S), createVector(0,1,-1))
rotateX(-0.5);
rotateY(-frameCount / 600);
drawTrees();
drawBassin();
drawSnake();
}
function drawSnake() {
push();
specularMaterial(255);
shininess(20);
metalness(50);
for (let f = 0, i = 0; f < 1; f += 1 / 100, i++) {
const a =
map(f, 0, 1, -0.35 * TAU, -1.65 * TAU) -
frameCount / 50 -
sin(frameCount / 10 + i / 5) / 10;
const dia = f * maxDia;
const x = cos(a) * snRadi;
const y = -maxDia / 3;
const z = sin(a) * snRadi;
push();
fill(CLRS[i % CLRS.length]);
translate(x, y, z);
//sphere(dia);
rotateX(HALF_PI);
rotateZ(0 * HALF_PI + a);
cylinder(dia / 2, dia, 24, 1, false, false);
pop();
}
pop();
}
function drawTrees() {
// trees
for (let tree of trees) {
tree.show();
}
}
function drawBassin() {
push();
push();
fill("#445533");
translate(0, S / 5 + 1, 0);
rotateX(HALF_PI);
circle(0, 0, 6 * S);
pop();
fill("#3388cc44");
translate(0, S/10, 0);
if (showWater) box(S, S/5, S); // box(S - 16, S / 5 - 1, S - 16); // water enabe/disable
if (false) {
fill(128, 72);
translate(0, 0, S / 2);
box(S, S / 5, 15);
translate(0, 0, -S);
box(S, S / 5, 15);
translate(S / 2, 0, S / 2);
box(15, S / 5, S);
translate(-S, 0, 0);
box(15, S / 5, S);
}
pop();
const N = 20;
const T = S / N;
if (showTiles) { // draw tiles or not; not visible even when water is transparent
for (let j = 0; j < N; j++) {
beginShape(TRIANGLES); // TRIANGLE_STRIP
for (let i = 0; i < N; i++) {
push();
const x = -S/2 + i*T + T/2;
const y = 2 * S / 10;
const z = -S/2 + j*T + T/2;
const n = noise(S + x/123, S + z/213, frameCount/64);
const clr = lerpColor(color("cyan"), color("darkgreen"), n);
translate(x, y, z);
fill(clr);
box(T, 2, T);
pop();
}
endShape()
}
}
if (true) { // draw water
fill("#3388cc44");
for (let j = 0; j < N; j++) {
beginShape(TRIANGLE_STRIP);
for (let i = 0; i <= N; i++) {
const v1 = getWaterLevel(i, j, S, T);
const v2 = getWaterLevel(i, j+1, S, T);
vertex(v1.x, v1.y, v1.z)
vertex(v2.x, v2.y, v2.z)
}
endShape();
}
if (false) {
beginShape(TRIANGLE_STRIP);
for (let i = 0; i <= N; i++) {
const v = getWaterLevel(i, 0, S, T);
vertex(v.x, v.y, v.z)
vertex(v.x, S/5, v.z)
}
endShape();
beginShape(TRIANGLE_STRIP);
for (let i = 0; i <= N; i++) {
const v = getWaterLevel(i, N-1, S, T);
vertex(v.x, v.y, v.z)
vertex(v.x, S/5, v.z)
}
endShape();
beginShape(TRIANGLE_STRIP);
for (let j = 0; j < N; j++) {
const v = getWaterLevel(0, j, S, T);
vertex(v.x, v.y, v.z)
vertex(v.x, S/5, v.z)
}
endShape();
beginShape(TRIANGLE_STRIP);
for (let j = 0; j < N; j++) {
const v = getWaterLevel(N, j, S, T);
vertex(v.x, v.y, v.z)
vertex(v.x, S/5, v.z)
}
endShape();
}
}
}
function getWaterLevel(i, j, S, T) {
const x = -S/2 + i*T;
const z = -S/2 + j*T;
const n = noise(S + x/123, S + z/213, frameCount/64);
const y = (n-0.5)*T;
return {x, y, z};
}
function placeTrees(n) {
let arr = [];
for (let i = 0; i < n; i++) {
const a = random(TAU)
const r = S * random(1.1, 1.7)
const x = cos(a) * r;
const y = S/5;
const z = sin(a) * r;
const newTree = new SN_Tree({x, y, z}, S/random(7, 10), S*random(0.3, 0.5));
arr.push(newTree);
}
return arr;
}
function doubleClicked() {
if (mouseButton != RIGHT) setup();
}