xxxxxxxxxx
let geom
let blurRenderer
function setup() {
createCanvas(windowWidth, windowHeight, WEBGL)
// pixelDensity(2)
background(10)
blurRenderer = createGaussianBlurRenderer()
blurRenderer.setIntensity(0.05)
blurRenderer.setSamples(20)
blurRenderer.setDof(100)
}
function makeGeom() {
if (geom) freeGeometry(geom)
let shape = csg(() => {
box(200)
})
for (let i = 0; i < 4; i++) {
shape = shape.union(() => {
push()
translate(random(-1, 1)*200, random(-1, 1)*200, random(-1, 1)*200)
rotateX(random(-1,1)*PI)
rotateY(random(-1,1)*PI)
box(random(50, 300))
pop()
})
}
geom = shape.done()
for (let i = 0; i < 2; i++) {
geom = subdiv(geom)
}
geom.clearColors()
}
let lastShapeTime = -100000
const period = 8000
function draw() {
let t = millis()
if (t - lastShapeTime >= period) {
makeGeom()
t = millis()
lastShapeTime = t
}
blurRenderer.draw(() => {
background(10)
push()
rotateY(t * 0.0001)
rotateX(t * -0.00005)
fill(10)
const light =
map(t, lastShapeTime, lastShapeTime + 1000, 0, 1, true) *
map(t, lastShapeTime + period - 1000, lastShapeTime + period, 1, 0, true)
stroke(lerpColor(color(10), color('#FFD840'), light))
scale(min(width, height)/800)
model(geom)
pop()
push()
translate(0, 0, 100)
blurRenderer.focusHere()
pop()
})
}
function subdiv(src, { smoothness = 1 } = {}) {
const fmt = (val) => Math.round(val*1000)/1000
const vertKey = (v) => `${fmt(v.x)},${fmt(v.y)},${fmt(v.z)}`
const edgeKey = (e) => e.join(',')
const vertIndices = {}
const verts = []
const edges = {}
for (const v of src.vertices) {
const key = vertKey(v)
if (!vertIndices[key]) {
vertIndices[key] = verts.length
verts.push(v)
}
}
const faces = src.faces.map(
(f) => f.map((i) => vertIndices[vertKey(src.vertices[i])])
)
const faceEdges = []
for (const face of faces) {
const currentFaceEdges = []
for (let i = 0; i < 3; i++) {
const j = (i+1)%3
const indices = [face[i], face[j]]
const key = edgeKey(indices)
const twinKey = edgeKey([face[j], face[i]])
const edge = {
face,
indices,
twin: () => edges[twinKey],
next: () => {
return edges[edgeKey([
face[j], face[(j+1)%3]
])]
}
}
edges[key] = edge
currentFaceEdges.push(edge)
}
faceEdges.push(currentFaceEdges)
}
const geom = buildGeometry(() => {
for (const [i, e] of faceEdges.entries()) {
const newFace = []
for (let i = 0; i < 3; i++) {
const prevIdx = e[i].indices[0]
const nextIdx = e[i].indices[1]
const otherIdx1 = e[i].next().indices[1]
const otherIdx2 = e[i].twin() ? e[i].twin().next().indices[1] : undefined
const prev = verts[prevIdx]
const next = verts[nextIdx]
const other1 = verts[otherIdx1]
const other2 = otherIdx2 !== undefined ? verts[otherIdx2] : undefined
// const prevUV = src.uvs[prevIdx]
// const nextUV = src.uvs[nextIdx]
// const prevNormal = src.vertexNormals[prevIdx]
// const nextNormal = src.vertexNormals[nextIdx]
const sources = [
[prev, 3/8],
[next, 3/8],
[other1, 1/8 * smoothness],
other2 ? [[other2, 1/8 * smoothness]] : []), (
]
const totalWeight = sources
.map(([_, weight]) => weight)
.reduce((acc, next) => acc + next, 0)
const connectedToPrev = Object.values(edges)
.filter((e) => e.indices.includes(prevIdx))
.map((e) => e.indices[0] === prevIdx ? e.indices[1] : e.indices[0])
const connectionWeight = connectedToPrev.length > 3
? (3 / (8 * connectedToPrev.length))
: (3 / 16)
newFace.push(
connectedToPrev
.map((idx) => verts[idx].copy().mult(connectionWeight))
.reduce(
(acc, next) => acc.add(next),
prev.copy().mult(1 - connectedToPrev.length * connectionWeight)
)
)
newFace.push(
sources
.map(([src, weight]) => src.copy().mult(weight))
.reduce((acc, next) => acc.add(next), createVector(0,0,0))
.div(totalWeight)
)
}
/*
5
0 *---*---* 4
\ / \ /
1 *---* 3
\ /
2 *
*/
const indices = [
[0, 1, 5],
[5, 3, 4],
[1, 2, 3],
[1, 3, 5]
]
beginShape(TRIANGLES)
for (const face of indices) {
for (const i of face) {
const v = newFace[i]
vertex(v.x, v.y, v.z)
}
}
endShape()
}
})
// geom.computeNormals(SMOOTH)
return geom
}