xxxxxxxxxx
let fork
let warp
let env
let dome
const positions = []
function preload() {
env = loadImage('sunset.jpg')
}
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL);
const normalToTexture = (v) => {
// x = r sin(phi) cos(theta)
// y = r cos(phi)
// z = r sin(phi) sin(theta)
let phi = acos( v.y );
// if phi is 0, then there are no x, z components
let theta = 0.0;
// else
theta = acos(v.x / sin(phi));
let sinTheta = v.z / sin(phi);
if (sinTheta < 0.0) {
// Turn it into -theta, but in the 0-2PI range
theta = 2.0 * PI - theta;
}
theta = theta / (2.0 * 3.14159);
phi = phi / 3.14159 ;
return {
u: (theta + 0.75) % 1,
v: 1.0 - phi
};
}
dome = buildGeometry(() => sphere(3000))
for (let i = 0; i < dome.vertices.length; i++) {
const n = dome.vertices[i].copy().mult(-1).normalize()
const { u, v } = normalToTexture(n)
if (dome.vertices[i].y > 0) {
dome.vertices[i].y = 0
}
dome.uvs[i*2] = u
dome.uvs[i*2+1] = 1 - v
}
for (let i = 0; i < 40; i++) {
positions.push({
x: random(-1, 1) * 700,
z: random(-1, 1) * 700,
a: random(TWO_PI),
})
}
noStroke()
fork = buildGeometry(() => {
const pts = [
createVector(-5, 0),
createVector(-5, -250),
createVector(-25, -250),
createVector(-25, -350),
createVector(-20, -350),
createVector(-20, -255),
]
pts.push(pts.map(v => createVector(-v.x, v.y)).reverse())
for (const side of [-1, 1]) {
push()
scale(1, 1, side)
beginShape()
for (let i = 1; i < pts.length; i++) {
for (let j = 0; j < (i === pts.length-1 ? 2 : 1); j++) { //
const pt = p5.Vector.lerp(pts[i-1], pts[i], j)
vertex(pt.x, pt.y, 5)
}
}
endShape()
pop()
}
beginShape(QUAD_STRIP)
for (let i = 0; i <= pts.length; i++) {
const pt = pts[i%pts.length]
for (const side of [-1, 1]) {
vertex(pt.x, pt.y, side*5)
}
}
endShape()
})
fork.clearColors()
for (let i = 0; i < 5; i++) {
fork = subdiv(fork)
}
fork.computeNormals()
warp = createWarp(({ glsl, position }) => {
let offsetted = position
offsetted = offsetted.add(glsl.vec3(
0,
0,
glsl.sin(offsetted.y().mult(offsetted.y()).mult(0.00005)).pow(4).mult(2)
))
for (let i = 0; i < 4; i++) {
const s = 1.5 / (i + 1)
const k = 0.001 * (i+1)
const y = offsetted.y().mult(offsetted.y().add(30)).mult(0.2)
const x = offsetted.x().mult(3.456)
const z = offsetted.z()
offsetted = offsetted.add(glsl.vec3(
glsl.sin(y.mult(k).add(random(TWO_PI))).mult(s),
glsl.sin(z.mult(k).add(random(TWO_PI))).mult(s),
glsl.sin(x.mult(k).add(random(TWO_PI))).mult(s),
))
offsetted = offsetted.add(glsl.vec3(
glsl.sin(z.mult(k).add(random(TWO_PI))).mult(s),
glsl.sin(x.mult(k).add(random(TWO_PI))).mult(s),
glsl.sin(y.mult(k).add(random(TWO_PI))).mult(s),
))
}
return offsetted.sub(position)
})
remap = createFilterShader(`precision highp float;
varying vec2 vTexCoord;
uniform sampler2D tex0;
void main() {
vec4 color = texture2D(tex0, vTexCoord);
color.rgb *= vec3(1., 0.8, 0.6);
color.rgb = smoothstep(vec3(0.), vec3(1.), color.rgb);
gl_FragColor = vec4(color.rgb, 1.0);
}`)
}
function draw() {
background('#FFAA00')
const r = 800
const t = millis() * 0.0001
camera(r*cos(t), -80, r*sin(t), 0, -250, 0)
push()
texture(env)
model(dome)
pop()
push()
imageLight(env)
fill(255)
directionalLight(100, 100, 100, -1, 0.2, 1)
metalness(400)
warp()
for (const { x, z, a } of positions) {
push()
translate(x, 0, z)
rotateY(a)
model(fork)
pop()
}
pop()
filter(remap)
}