mirror of
https://github.com/seigler/generative
synced 2025-07-26 06:46:10 +00:00
Add sketch 4: lenses
This commit is contained in:
parent
f09b4c66f0
commit
d3cbff29fc
5 changed files with 327 additions and 5 deletions
1
app/assets/4/index.html
Symbolic link
1
app/assets/4/index.html
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../sketch-template.html
|
|
@ -9,11 +9,12 @@
|
|||
<body>
|
||||
<main>
|
||||
<h1>P5.js generative art</h1>
|
||||
<ol>
|
||||
<li><a class="sketch" href="1/">gradient burst</a></li>
|
||||
<li><a class="sketch" href="2/">gradient jungle</a></li>
|
||||
<li><a class="sketch" href="3/">peanut butter and jelly</a></li>
|
||||
</ol>
|
||||
<ul>
|
||||
<li>2019-11-05 - <a class="sketch" href="1/">gradient burst</a></li>
|
||||
<li>2019-11-07 - <a class="sketch" href="2/">gradient jungle</a></li>
|
||||
<li>2019-11-09 - <a class="sketch" href="3/">peanut butter and jelly</a></li>
|
||||
<li>2019-11-10 - <a class="sketch" href="4/">lenses</a></li>
|
||||
</ul>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
|
37
app/assets/shaders/displacement.frag
Normal file
37
app/assets/shaders/displacement.frag
Normal file
|
@ -0,0 +1,37 @@
|
|||
precision mediump float;
|
||||
|
||||
// lets grab texcoords just for fun
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
// our texture and image coming from p5
|
||||
uniform sampler2D u_src;
|
||||
uniform sampler2D u_map;
|
||||
|
||||
// how much to displace by (controlled by mouse)
|
||||
uniform float u_intensity;
|
||||
|
||||
void main() {
|
||||
|
||||
vec2 uv = vTexCoord;
|
||||
// the texture is loaded upside down and backwards by default so lets flip it
|
||||
uv = 1.0 - uv;
|
||||
|
||||
// get the displacement map as a vec4 using texture2D
|
||||
vec4 mapTex = texture2D(u_map, uv);
|
||||
|
||||
// lets get the average color of the rgb values
|
||||
float avg = dot(mapTex.rgb, vec3(0.33333));
|
||||
|
||||
// then spread it between -1 and 1
|
||||
avg = avg * 2.0 - 1.0;
|
||||
|
||||
// we will displace the image by the average color times the amt of displacement
|
||||
float disp = avg * u_intensity;
|
||||
|
||||
// displacement works by moving the texture coordinates of one image with the colors of another image
|
||||
// add the displacement to the texture coordinages
|
||||
vec4 srcTex = texture2D(u_src, uv + disp);
|
||||
|
||||
// output the image
|
||||
gl_FragColor = srcTex;
|
||||
}
|
278
app/sketches/4.js
Normal file
278
app/sketches/4.js
Normal file
|
@ -0,0 +1,278 @@
|
|||
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
|
||||
|
||||
sketch.preload = () => {
|
||||
shaders.whiteNoise = sketch.loadShader(
|
||||
'../shaders/base.vert',
|
||||
'../shaders/white-noise.frag'
|
||||
);
|
||||
shaders.displacement = sketch.loadShader(
|
||||
'../shaders/base.vert',
|
||||
'../shaders/displacement.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'
|
||||
);
|
||||
lib.voronoi = new Voronoi()
|
||||
}
|
||||
|
||||
sketch.setup = () => {
|
||||
filenamePrefix = 'seigler-p5-3-lenses';
|
||||
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 = 1;
|
||||
|
||||
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.buffer = sketch.createGraphics(width, height);
|
||||
layers.buffer.colorMode(sketch.HSL, 1);
|
||||
|
||||
layers.cells = sketch.createGraphics(width, height);
|
||||
layers.cells.colorMode(sketch.HSL, 1);
|
||||
layers.cells.noStroke();
|
||||
|
||||
layers.noise = sketch.createGraphics(width, height, sketch.WEBGL);
|
||||
|
||||
layers.displacement = 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));
|
||||
sketch.blendMode(sketch.BLEND);
|
||||
// sketch.background(0.5);
|
||||
|
||||
let stripeAngle = sketch.random(0, Math.PI);
|
||||
let stripeWidth = Math.min(width, height) / sketch.random(10, 80);
|
||||
let stripeLength = Math.max(width, height) * Math.SQRT2;
|
||||
let numStripes = Math.ceil(Math.SQRT2 * stripeLength / stripeWidth);
|
||||
let stripeHue = sketch.random();
|
||||
let ox = width/2, oy = height/2;
|
||||
let dx = Math.cos(stripeAngle) * stripeLength / 2;
|
||||
let dy = Math.sin(stripeAngle) * stripeLength / 2;
|
||||
layers.buffer.strokeCap(sketch.SQUARE);
|
||||
for (let i = Math.ceil(numStripes / 2); i > 0; i--) {
|
||||
layers.buffer.stroke(stripeHue, 0.5, 0.2 + 0.1 * (i % 2));
|
||||
layers.buffer.strokeWeight((i * 2 - 1) * stripeWidth);
|
||||
layers.buffer.line(ox - dx, oy - dy, ox + dx, oy + dy);
|
||||
}
|
||||
|
||||
// square pixels per circle, helps with gridding
|
||||
sketch.blendMode(sketch.BLEND);
|
||||
let unit = Math.min(width, height) / Math.round(sketch.random(3, 10));
|
||||
let rows = Math.max(1, Math.round(height / unit / Math.sin(Math.PI / 3))) + 1;
|
||||
let cols = Math.max(1, Math.round(width / unit)) + 1;
|
||||
let noiseOffset = unit * 200 + Math.SQRT2;
|
||||
let gridPoints = [];
|
||||
for (let index = 0; index < rows * cols; index++) {
|
||||
let col = index % cols;
|
||||
let row = Math.floor(index / cols);
|
||||
let noise = noiseResolution.map(
|
||||
(resolution, noiseIndex) => {
|
||||
// let gridScale = resolution / Math.min(rows, cols);
|
||||
return sketch.noise(
|
||||
noiseOffset * (noiseIndex + 1) + (row - rows / 2) * resolution,
|
||||
noiseOffset * (noiseIndex + 1) + (col - cols / 2) * resolution
|
||||
)
|
||||
}
|
||||
);
|
||||
gridPoints.push({
|
||||
row,
|
||||
col,
|
||||
noise,
|
||||
});
|
||||
}
|
||||
gridPoints.forEach(point => {
|
||||
let { col, row, noise: [n0, n1, n2, n3] } = point;
|
||||
point.x = (
|
||||
width / (cols - 1) * col
|
||||
+ (row % 2 - 0.5) * unit / 2
|
||||
+ 1 * n0 * unit * Math.cos(Math.PI * 2 * flattenPerlin(n1))
|
||||
);
|
||||
point.y = (
|
||||
height / (rows - 1) * row
|
||||
+ 1 * n0 * unit * Math.sin(Math.PI * 2 * flattenPerlin(n1))
|
||||
);
|
||||
});
|
||||
let bbox = {
|
||||
xl: 0 - unit / 2,
|
||||
xr: width + unit / 2,
|
||||
yt: 0 - unit / 2,
|
||||
yb: height + unit / 2
|
||||
};
|
||||
let diagram = lib.voronoi.compute(gridPoints, bbox);
|
||||
|
||||
// let's draw cells
|
||||
layers.cells.background(0.5);
|
||||
diagram.cells.forEach(cell => {
|
||||
if (cell.halfedges.length >= 3) {
|
||||
layers.cells.fill(cell.site.noise[2]);
|
||||
layers.cells.beginShape();
|
||||
for(let i = 0; i < cell.halfedges.length + 1; i++) {
|
||||
const he = cell.halfedges[i % cell.halfedges.length];
|
||||
const {x: ax, y: ay} = he.getStartpoint()
|
||||
const {x: bx, y: by} = he.getEndpoint()
|
||||
if (i === 0) {
|
||||
layers.cells.vertex(
|
||||
sketch.lerp(sketch.lerp(ax, bx, 0.5), cell.site.x, 0.1),
|
||||
sketch.lerp(sketch.lerp(ay, by, 0.5), cell.site.y, 0.1)
|
||||
);
|
||||
first = false;
|
||||
} else {
|
||||
// check angular edge length
|
||||
layers.cells.quadraticVertex(
|
||||
sketch.lerp(ax, cell.site.x, 0.1),
|
||||
sketch.lerp(ay, cell.site.y, 0.1),
|
||||
sketch.lerp(sketch.lerp(ax, bx, 0.5), cell.site.x, 0.1),
|
||||
sketch.lerp(sketch.lerp(ay, by, 0.5), cell.site.y, 0.1)
|
||||
);
|
||||
}
|
||||
}
|
||||
layers.cells.endShape();
|
||||
}
|
||||
});
|
||||
|
||||
// blur the cells
|
||||
let blurSize = unit / 300;
|
||||
for (let pass = 0; pass < blurQuality; pass++) {
|
||||
let radius = (blurQuality - pass) * blurSize / blurQuality;
|
||||
layers.blur1.shader(shaders.blurH);
|
||||
shaders.blurH.setUniform('tex0', pass == 0 ? layers.cells : layers.blur2);
|
||||
shaders.blurH.setUniform('texelSize', [radius/width, radius/height]);
|
||||
shaders.blurH.setUniform('direction', [1.0, 0.0]);
|
||||
layers.blur1.rect(0, 0, width, height);
|
||||
layers.blur2.shader(shaders.blurV);
|
||||
shaders.blurV.setUniform('tex0', layers.blur1);
|
||||
shaders.blurV.setUniform('texelSize', [radius/width, radius/height]);
|
||||
shaders.blurV.setUniform('direction', [0.0, 1.0]);
|
||||
layers.blur2.rect(0, 0, width, height);
|
||||
}
|
||||
|
||||
layers.cells.image(layers.blur2, 0, 0, width, height);
|
||||
|
||||
layers.displacement.shader(shaders.displacement);
|
||||
shaders.displacement.setUniform('u_src', layers.buffer);
|
||||
shaders.displacement.setUniform('u_map', layers.cells);
|
||||
shaders.displacement.setUniform('u_intensity', 10 / unit);
|
||||
layers.displacement.rect(0, 0, width, height);
|
||||
sketch.blendMode(sketch.BLEND);
|
||||
sketch.image(
|
||||
layers.displacement,
|
||||
Math.floor(-width * overdraw / 2),
|
||||
Math.floor(-height * overdraw / 2)
|
||||
);
|
||||
|
||||
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.blendMode(sketch.OVERLAY);
|
||||
sketch.image(layers.noise, 0, 0);
|
||||
|
||||
// sketch.stroke(0);
|
||||
// sketch.strokeWeight(4);
|
||||
// diagram.vertices.forEach(vertex => {
|
||||
// sketch.point(vertex.x, vertex.y);
|
||||
// });
|
||||
|
||||
// diagram.edges.forEach(({va, vb}) => {
|
||||
// sketch.line(
|
||||
// va.x,
|
||||
// va.y,
|
||||
// vb.x,
|
||||
// vb.y
|
||||
// );
|
||||
// });
|
||||
|
||||
// sketch.stroke('#E00');
|
||||
// gridPoints.forEach(({x, y}) => {
|
||||
// sketch.point(x, y);
|
||||
// });
|
||||
}
|
||||
|
||||
// Fisher-Yates shuffle
|
||||
function shuffle(array) {
|
||||
var i = 0, j = 0, temp = null;
|
||||
|
||||
for (i = array.length - 1; i > 0; i -= 1) {
|
||||
j = Math.floor(sketch.random() * (i + 1));
|
||||
temp = array[i];
|
||||
array[i] = array[j];
|
||||
array[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
// 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));
|
||||
}
|
||||
});
|
|
@ -35,6 +35,11 @@ code {
|
|||
background-color: #222;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue