mirror of
https://github.com/seigler/generative
synced 2025-07-26 06:46:10 +00:00
Sketch 7, Estrellas
This commit is contained in:
parent
475d992347
commit
2e78c0778e
5 changed files with 409 additions and 0 deletions
237
app/7/delaunay.js
Normal file
237
app/7/delaunay.js
Normal file
|
@ -0,0 +1,237 @@
|
|||
// from https://github.com/ironwallaby/delaunay
|
||||
var Delaunay;
|
||||
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
var EPSILON = 1.0 / 1048576.0;
|
||||
|
||||
function supertriangle(vertices) {
|
||||
var xmin = Number.POSITIVE_INFINITY,
|
||||
ymin = Number.POSITIVE_INFINITY,
|
||||
xmax = Number.NEGATIVE_INFINITY,
|
||||
ymax = Number.NEGATIVE_INFINITY,
|
||||
i, dx, dy, dmax, xmid, ymid;
|
||||
|
||||
for(i = vertices.length; i--; ) {
|
||||
if(vertices[i][0] < xmin) xmin = vertices[i][0];
|
||||
if(vertices[i][0] > xmax) xmax = vertices[i][0];
|
||||
if(vertices[i][1] < ymin) ymin = vertices[i][1];
|
||||
if(vertices[i][1] > ymax) ymax = vertices[i][1];
|
||||
}
|
||||
|
||||
dx = xmax - xmin;
|
||||
dy = ymax - ymin;
|
||||
dmax = Math.max(dx, dy);
|
||||
xmid = xmin + dx * 0.5;
|
||||
ymid = ymin + dy * 0.5;
|
||||
|
||||
return [
|
||||
[xmid - 20 * dmax, ymid - dmax],
|
||||
[xmid , ymid + 20 * dmax],
|
||||
[xmid + 20 * dmax, ymid - dmax]
|
||||
];
|
||||
}
|
||||
|
||||
function circumcircle(vertices, i, j, k) {
|
||||
var x1 = vertices[i][0],
|
||||
y1 = vertices[i][1],
|
||||
x2 = vertices[j][0],
|
||||
y2 = vertices[j][1],
|
||||
x3 = vertices[k][0],
|
||||
y3 = vertices[k][1],
|
||||
fabsy1y2 = Math.abs(y1 - y2),
|
||||
fabsy2y3 = Math.abs(y2 - y3),
|
||||
xc, yc, m1, m2, mx1, mx2, my1, my2, dx, dy;
|
||||
|
||||
/* Check for coincident points */
|
||||
if(fabsy1y2 < EPSILON && fabsy2y3 < EPSILON)
|
||||
throw new Error("Eek! Coincident points!");
|
||||
|
||||
if(fabsy1y2 < EPSILON) {
|
||||
m2 = -((x3 - x2) / (y3 - y2));
|
||||
mx2 = (x2 + x3) / 2.0;
|
||||
my2 = (y2 + y3) / 2.0;
|
||||
xc = (x2 + x1) / 2.0;
|
||||
yc = m2 * (xc - mx2) + my2;
|
||||
}
|
||||
|
||||
else if(fabsy2y3 < EPSILON) {
|
||||
m1 = -((x2 - x1) / (y2 - y1));
|
||||
mx1 = (x1 + x2) / 2.0;
|
||||
my1 = (y1 + y2) / 2.0;
|
||||
xc = (x3 + x2) / 2.0;
|
||||
yc = m1 * (xc - mx1) + my1;
|
||||
}
|
||||
|
||||
else {
|
||||
m1 = -((x2 - x1) / (y2 - y1));
|
||||
m2 = -((x3 - x2) / (y3 - y2));
|
||||
mx1 = (x1 + x2) / 2.0;
|
||||
mx2 = (x2 + x3) / 2.0;
|
||||
my1 = (y1 + y2) / 2.0;
|
||||
my2 = (y2 + y3) / 2.0;
|
||||
xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
|
||||
yc = (fabsy1y2 > fabsy2y3) ?
|
||||
m1 * (xc - mx1) + my1 :
|
||||
m2 * (xc - mx2) + my2;
|
||||
}
|
||||
|
||||
dx = x2 - xc;
|
||||
dy = y2 - yc;
|
||||
return {i: i, j: j, k: k, x: xc, y: yc, r: dx * dx + dy * dy};
|
||||
}
|
||||
|
||||
function dedup(edges) {
|
||||
var i, j, a, b, m, n;
|
||||
|
||||
for(j = edges.length; j; ) {
|
||||
b = edges[--j];
|
||||
a = edges[--j];
|
||||
|
||||
for(i = j; i; ) {
|
||||
n = edges[--i];
|
||||
m = edges[--i];
|
||||
|
||||
if((a === m && b === n) || (a === n && b === m)) {
|
||||
edges.splice(j, 2);
|
||||
edges.splice(i, 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Delaunay = {
|
||||
triangulate: function(vertices, key) {
|
||||
var n = vertices.length,
|
||||
i, j, indices, st, open, closed, edges, dx, dy, a, b, c;
|
||||
|
||||
/* Bail if there aren't enough vertices to form any triangles. */
|
||||
if(n < 3)
|
||||
return [];
|
||||
|
||||
/* Slice out the actual vertices from the passed objects. (Duplicate the
|
||||
* array even if we don't, though, since we need to make a supertriangle
|
||||
* later on!) */
|
||||
vertices = vertices.slice(0);
|
||||
|
||||
if(key)
|
||||
for(i = n; i--; )
|
||||
vertices[i] = vertices[i][key];
|
||||
|
||||
/* Make an array of indices into the vertex array, sorted by the
|
||||
* vertices' x-position. Force stable sorting by comparing indices if
|
||||
* the x-positions are equal. */
|
||||
indices = new Array(n);
|
||||
|
||||
for(i = n; i--; )
|
||||
indices[i] = i;
|
||||
|
||||
indices.sort(function(i, j) {
|
||||
var diff = vertices[j][0] - vertices[i][0];
|
||||
return diff !== 0 ? diff : i - j;
|
||||
});
|
||||
|
||||
/* Next, find the vertices of the supertriangle (which contains all other
|
||||
* triangles), and append them onto the end of a (copy of) the vertex
|
||||
* array. */
|
||||
st = supertriangle(vertices);
|
||||
vertices.push(st[0], st[1], st[2]);
|
||||
|
||||
/* Initialize the open list (containing the supertriangle and nothing
|
||||
* else) and the closed list (which is empty since we havn't processed
|
||||
* any triangles yet). */
|
||||
open = [circumcircle(vertices, n + 0, n + 1, n + 2)];
|
||||
closed = [];
|
||||
edges = [];
|
||||
|
||||
/* Incrementally add each vertex to the mesh. */
|
||||
for(i = indices.length; i--; edges.length = 0) {
|
||||
c = indices[i];
|
||||
|
||||
/* For each open triangle, check to see if the current point is
|
||||
* inside it's circumcircle. If it is, remove the triangle and add
|
||||
* it's edges to an edge list. */
|
||||
for(j = open.length; j--; ) {
|
||||
/* If this point is to the right of this triangle's circumcircle,
|
||||
* then this triangle should never get checked again. Remove it
|
||||
* from the open list, add it to the closed list, and skip. */
|
||||
dx = vertices[c][0] - open[j].x;
|
||||
if(dx > 0.0 && dx * dx > open[j].r) {
|
||||
closed.push(open[j]);
|
||||
open.splice(j, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we're outside the circumcircle, skip this triangle. */
|
||||
dy = vertices[c][1] - open[j].y;
|
||||
if(dx * dx + dy * dy - open[j].r > EPSILON)
|
||||
continue;
|
||||
|
||||
/* Remove the triangle and add it's edges to the edge list. */
|
||||
edges.push(
|
||||
open[j].i, open[j].j,
|
||||
open[j].j, open[j].k,
|
||||
open[j].k, open[j].i
|
||||
);
|
||||
open.splice(j, 1);
|
||||
}
|
||||
|
||||
/* Remove any doubled edges. */
|
||||
dedup(edges);
|
||||
|
||||
/* Add a new triangle for each edge. */
|
||||
for(j = edges.length; j; ) {
|
||||
b = edges[--j];
|
||||
a = edges[--j];
|
||||
open.push(circumcircle(vertices, a, b, c));
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy any remaining open triangles to the closed list, and then
|
||||
* remove any triangles that share a vertex with the supertriangle,
|
||||
* building a list of triplets that represent triangles. */
|
||||
for(i = open.length; i--; )
|
||||
closed.push(open[i]);
|
||||
open.length = 0;
|
||||
|
||||
for(i = closed.length; i--; )
|
||||
if(closed[i].i < n && closed[i].j < n && closed[i].k < n)
|
||||
open.push(closed[i].i, closed[i].j, closed[i].k);
|
||||
|
||||
/* Yay, we're done! */
|
||||
return open;
|
||||
},
|
||||
contains: function(tri, p) {
|
||||
/* Bounding box test first, for quick rejections. */
|
||||
if((p[0] < tri[0][0] && p[0] < tri[1][0] && p[0] < tri[2][0]) ||
|
||||
(p[0] > tri[0][0] && p[0] > tri[1][0] && p[0] > tri[2][0]) ||
|
||||
(p[1] < tri[0][1] && p[1] < tri[1][1] && p[1] < tri[2][1]) ||
|
||||
(p[1] > tri[0][1] && p[1] > tri[1][1] && p[1] > tri[2][1]))
|
||||
return null;
|
||||
|
||||
var a = tri[1][0] - tri[0][0],
|
||||
b = tri[2][0] - tri[0][0],
|
||||
c = tri[1][1] - tri[0][1],
|
||||
d = tri[2][1] - tri[0][1],
|
||||
i = a * d - b * c;
|
||||
|
||||
/* Degenerate tri. */
|
||||
if(i === 0.0)
|
||||
return null;
|
||||
|
||||
var u = (d * (p[0] - tri[0][0]) - b * (p[1] - tri[0][1])) / i,
|
||||
v = (a * (p[1] - tri[0][1]) - c * (p[0] - tri[0][0])) / i;
|
||||
|
||||
/* If we're outside the tri, fail. */
|
||||
if(u < 0.0 || v < 0.0 || (u + v) > 1.0)
|
||||
return null;
|
||||
|
||||
return [u, v];
|
||||
}
|
||||
};
|
||||
|
||||
if(typeof module !== "undefined")
|
||||
module.exports = Delaunay;
|
||||
})();
|
159
app/7/index.js
Normal file
159
app/7/index.js
Normal file
|
@ -0,0 +1,159 @@
|
|||
const Delaunay = require('./delaunay.js');
|
||||
|
||||
new p5(sketch => {
|
||||
sketch.disableFriendlyErrors = false;
|
||||
// reused dimensions and a seed
|
||||
let seed, width, height, noiseResolution, overdraw, blurQuality;
|
||||
const layers = {}; // offscreen layers
|
||||
const shaders = {}; // shaders
|
||||
const lib = {}; // libraries
|
||||
const assets = {}; // fonts, images, sound files
|
||||
|
||||
sketch.preload = () => {
|
||||
shaders.whiteNoise = sketch.loadShader(
|
||||
'../shaders/base.vert',
|
||||
'../shaders/white-noise.frag'
|
||||
);
|
||||
// shaders.blurH = sketch.loadShader(
|
||||
// '../shaders/base.vert',
|
||||
// '../shaders/blur-two-pass.frag'
|
||||
// );
|
||||
// shaders.blurV = sketch.loadShader(
|
||||
// '../shaders/base.vert',
|
||||
// '../shaders/blur-two-pass.frag'
|
||||
// );
|
||||
}
|
||||
|
||||
sketch.setup = () => {
|
||||
filenamePrefix = 'seigler-p5-7-estrellas-';
|
||||
overdraw = 0.1;
|
||||
width = Math.floor(sketch.windowWidth * (1 + overdraw));
|
||||
height = Math.floor(sketch.windowHeight * (1 + overdraw));
|
||||
noiseResolution = [0.2, 0.1, 0.05, 2];
|
||||
blurQuality = 2;
|
||||
|
||||
window.onhashchange = () => {
|
||||
seed = window.location.hash.substr(1);
|
||||
generate();
|
||||
};
|
||||
|
||||
seed = window.location.hash.substr(1);
|
||||
sketch.colorMode(sketch.HSL, 1);
|
||||
|
||||
sketch.createCanvas(sketch.windowWidth, sketch.windowHeight);
|
||||
|
||||
layers.stars = sketch.createGraphics(width, height);
|
||||
layers.stars.colorMode(sketch.HSL, 1);
|
||||
|
||||
layers.noise = sketch.createGraphics(width, height, sketch.WEBGL);
|
||||
|
||||
// layers.blur1 = sketch.createGraphics(width, height, sketch.WEBGL);
|
||||
// layers.blur2 = sketch.createGraphics(width, height, sketch.WEBGL);
|
||||
|
||||
generate();
|
||||
};
|
||||
|
||||
sketch.draw = () => {
|
||||
};
|
||||
|
||||
sketch.keyReleased = () => {
|
||||
if (sketch.key == ' ') {
|
||||
seed = null;
|
||||
generate();
|
||||
} else if (sketch.key == 's') {
|
||||
sketch.saveCanvas(filenamePrefix + seed + '.jpg', 'jpg');
|
||||
}
|
||||
};
|
||||
|
||||
sketch.doubleClicked = () => {
|
||||
seed = null;
|
||||
generate();
|
||||
};
|
||||
|
||||
let resizeTimer;
|
||||
sketch.windowResized = () => {
|
||||
clearTimeout(resizeTimer);
|
||||
resizeTimer = setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 100);
|
||||
};
|
||||
|
||||
function generate() {
|
||||
if (seed) {
|
||||
sketch.randomSeed(seed);
|
||||
} else {
|
||||
let seed = Math.floor(sketch.random(1000000000000));
|
||||
window.location.hash = seed;
|
||||
sketch.randomSeed(seed);
|
||||
}
|
||||
|
||||
sketch.noiseSeed(sketch.random(0, 1000000000));
|
||||
|
||||
layers.stars.clear();
|
||||
layers.stars.fill(1);
|
||||
layers.stars.noStroke();
|
||||
addStars(layers.stars);
|
||||
|
||||
sketch.blendMode(sketch.BLEND);
|
||||
sketch.background(0);
|
||||
layers.noise.shader(shaders.whiteNoise);
|
||||
shaders.whiteNoise.setUniform('u_resolution', [width, height]);
|
||||
shaders.whiteNoise.setUniform('u_alpha', 0.05);
|
||||
layers.noise.rect(0, 0, width, height);
|
||||
sketch.image(layers.stars, Math.round(-width * overdraw/2), Math.round(-height * overdraw/2));
|
||||
sketch.blendMode(sketch.OVERLAY);
|
||||
sketch.image(layers.noise, 0, 0);
|
||||
}
|
||||
|
||||
function addStars(layer) {
|
||||
const bigStars = new Array(Math.round(width * height / 2000));
|
||||
const littleStars = new Array(Math.round(width * height / 200));
|
||||
for (let i = 0; i < bigStars.length; i++) {
|
||||
bigStars[i] = [sketch.random(width), sketch.random(height)];
|
||||
}
|
||||
for (let i = 0; i < littleStars.length; i++) {
|
||||
littleStars[i] = [sketch.random(width), sketch.random(height)];
|
||||
}
|
||||
layer.noStroke();
|
||||
layer.fill(1);
|
||||
littleStars.forEach(star => {
|
||||
layer.circle(star[0], star[1], sketch.random(0.25, 0.5));
|
||||
});
|
||||
const triangles = Delaunay.triangulate(bigStars);
|
||||
layer.stroke(235/360, 0.82, 0.42, 0.28);
|
||||
layer.strokeWeight(2);
|
||||
layer.strokeCap(sketch.SQUARE);
|
||||
layer.noFill();
|
||||
for (let i = 0; i < triangles.length; i += 3) {
|
||||
if (sketch.random() > 0.85) {
|
||||
layer.triangle(
|
||||
bigStars[triangles[i ]][0], bigStars[triangles[i ]][1],
|
||||
bigStars[triangles[i + 1]][0], bigStars[triangles[i + 1]][1],
|
||||
bigStars[triangles[i + 2]][0], bigStars[triangles[i + 2]][1]
|
||||
);
|
||||
}
|
||||
}
|
||||
layer.noStroke();
|
||||
layer.fill(1);
|
||||
bigStars.forEach(star => {
|
||||
layer.circle(star[0], star[1], sketch.random(0.75, 2));
|
||||
});
|
||||
}
|
||||
|
||||
// give Perlin noise 0-1 a uniform distribution
|
||||
function flattenPerlin(x) {
|
||||
return 23.8615 * Math.pow(x, 5)
|
||||
- 59.6041 * Math.pow(x, 4)
|
||||
+ 47.2472 * Math.pow(x, 3)
|
||||
- 11.3053 * Math.pow(x, 2)
|
||||
+ 0.806219 * x - 0.00259101;
|
||||
}
|
||||
|
||||
// returns abs angle from a to b to c
|
||||
function three_point_angle(A,B,C) {
|
||||
var AB = Math.sqrt(Math.pow(B.x-A.x,2)+ Math.pow(B.y-A.y,2));
|
||||
var BC = Math.sqrt(Math.pow(B.x-C.x,2)+ Math.pow(B.y-C.y,2));
|
||||
var AC = Math.sqrt(Math.pow(C.x-A.x,2)+ Math.pow(C.y-A.y,2));
|
||||
return Math.acos((BC*BC+AB*AB-AC*AC)/(2*BC*AB));
|
||||
}
|
||||
});
|
7
app/7/index.static.hbs
Normal file
7
app/7/index.static.hbs
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
title: Cielo
|
||||
created: 2019-11-16
|
||||
index: 7
|
||||
_options:
|
||||
layout: app/layouts/sketch.hbs
|
||||
---
|
BIN
app/assets/7/example.jpg
Normal file
BIN
app/assets/7/example.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 224 KiB |
|
@ -14,6 +14,12 @@ _options:
|
|||
<body>
|
||||
<main>
|
||||
<h1>P5.js generative art</h1>
|
||||
{{> preview
|
||||
index="7"
|
||||
date="2019-11-16"
|
||||
title="Estrellas"
|
||||
alt="a field of stars with triangular blue constellations highlighted"
|
||||
}}
|
||||
{{> preview
|
||||
index="6"
|
||||
date="2019-11-14"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue