Public
Edited
Mar 25, 2024
Importers
22 stars
Insert cell
Insert cell
Insert cell
Insert cell
bnbThree({
// set all the parameters you need, see @makio135/bnb for a list of all the possible parameters
w: 540, h: 540,
numFrames: 120,
fps: 20,
record: true,
//video: true,
shutterAngle: .4,
samplesPerFrame: 16,
// createScene is a function that will be called with 3 parameters:
createScene: (THREE, sketch, globals) => {
// we init all our scene here
const scene = new THREE.Scene()

const geometry = new THREE.IcosahedronGeometry()
const material = new THREE.MeshNormalMaterial({ wireframe: true })
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)

const camera = new THREE.PerspectiveCamera(75, globals.w / globals.h, 0.1, 5)
camera.position.x = .3
camera.position.z = -1.8
camera.lookAt(mesh.position)

const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(globals.w, globals.h)
renderer.setClearColor(0x1f1f1f)

// createScene must return a function to update the scene
return (sketch, time, globals) => {
const angle = time * sketch.TAU
mesh.rotation.x = angle
mesh.rotation.y = angle

renderer.render(scene, camera)
// the update function must return the renderer
return renderer
}
}
})
Insert cell
Insert cell
await visibility(), bnbThree({
w: 540, h: 540,
numFrames: 200,
fps: 20,
record: true,
video: 'mp4',
chromaticAberration: 2,
shutterAngle: .3,
samplesPerFrame: 8,
// simple shaderPass to rotate the scene upside down
shaderPass: `
precision mediump float;
uniform vec2 u_resolution;
uniform sampler2D u_texture;

void main() {
vec2 uv = gl_FragCoord.xy / u_resolution;
gl_FragColor = texture2D(u_texture, uv);
}`,
createScene: (THREE, s, g) => {
// based on https://threejs.org/examples/#webgl_geometry_extrude_splines
const scene = new THREE.Scene()
scene.background = new THREE.Color(0x1E2630)
// create a simple texture using p5js
const pg = s.createGraphics(512, 512)
pg.background(255)
pg.noStroke()
pg.fill(0)
for(let i = 0; i < 10; i ++) {
pg.rect(i * pg.width/10, 0, pg.width/20, pg.height)
}
const alphaMap = new THREE.Texture(pg.canvas)
alphaMap.repeat = new THREE.Vector2(5, 1)
alphaMap.wrapS = alphaMap.wrapT = THREE.RepeatWrapping
alphaMap.needsUpdate = true // make sure to update the texture
const material = new THREE.MeshBasicMaterial({
wireframe: true,
alphaMap,
transparent: true,
side: THREE.BackSide
})
const geometry = new THREE.TubeGeometry(new curves.Curves.GrannyKnot(), 1500, 3, 50, true)
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)

const camera = new THREE.PerspectiveCamera(45, g.w / g.h, 0.001, 100)
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(g.w, g.h)
const direction = new THREE.Vector3()
const binormal = new THREE.Vector3()
const normal = new THREE.Vector3()
const position = new THREE.Vector3()
const lookAt = new THREE.Vector3()
return (s, t, g) => {
geometry.parameters.path.getPointAt(t, position)
// interpolation
const segments = geometry.tangents.length
const pickt = t * segments
const pick = Math.floor(pickt)
const pickNext = (pick + 1) % segments

binormal.subVectors(geometry.binormals[pickNext], geometry.binormals[pick])
binormal.multiplyScalar(pickt - pick).add(geometry.binormals[pick])

geometry.parameters.path.getTangentAt(t, direction)
// const offset = 3
const offset = -2.9

normal.copy(binormal).cross(direction)

// we move on a offset on its binormal
position.add(normal.clone().multiplyScalar(offset))

camera.position.copy(position)

// using arclength for stablization in look ahead
geometry.parameters.path.getPointAt((t + 6 / geometry.parameters.path.getLength()) % 1, lookAt)

// camera orientation 2 - up orientation via normal
camera.matrix.lookAt(camera.position, lookAt, normal)
camera.quaternion.setFromRotationMatrix(camera.matrix)
renderer.render(scene, camera)
return renderer
}
}
})
Insert cell
Insert cell
await visibility(), bnbThree({
numFrames: 120,
fps: 20,
record: true,
createScene: (THREE, sketch, globals) => {
const palette = ["#f1e8e6", "#f55951", "#edd2cb", "#361d32", "#543c52"]
const scene = new THREE.Scene()

// create an p5js offscreen canvas and use the canvas element as a texture
const pg = sketch.createGraphics(512, 512)
const tex = new THREE.Texture(pg.canvas)
tex.colorSpace = THREE.SRGBColorSpace
const material = new THREE.MeshPhongMaterial({
map: tex,
flatShading: true,
})
const geometry = new THREE.IcosahedronGeometry(1, 1)
// use random values for uvs
for(let i = 0; i < geometry.attributes.uv.array.length; i++) {
geometry.attributes.uv.array[i] = Math.random()
}
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)

const light = new THREE.HemisphereLight(0xffffff, 0x666666, 3.2)
scene.add(light)

const camera = new THREE.PerspectiveCamera(75, globals.w / globals.h, 0.1, 5)
camera.position.x = .3
camera.position.z = -1.8
camera.lookAt(mesh.position)

const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
renderer.setSize(globals.w, globals.h)

// createScene must return a function to update the scene
return (s, t, g) => {
// update p5js offscreen canvas
pg.background(palette[0])
pg.noStroke()
const prng = new PRNG()
const n = 8
for(let i = 0; i < n; i ++) {
pg.fill(palette[prng.rand(1, palette.length - 1)])
pg.rect(i * pg.width/n + t * pg.width - pg.width, 0, pg.width/(n * 2), pg.height)
pg.rect(i * pg.width/n + t * pg.width, 0, pg.width/(n * 2), pg.height)
}
s.push()
s.translate(g.w/2, g.h/2)
s.rotate(s.PI/3)
s.scale(1.4)
s.imageMode(s.CENTER)
s.image(pg, 0, 0, g.w, g.h)
s.pop()
// tell Threejs to update it
tex.needsUpdate = true
// animate our mesh
const angle = t * s.TAU
mesh.rotation.x = angle
mesh.rotation.y = angle

// render
renderer.render(scene, camera)
// the update function must return the renderer
return renderer
}
}
})
Insert cell
Insert cell
bnbThree({
// set all the parameters we need, see @makio135/bnb for a list of all the possible parameters
w: 540, h: 540,
numFrames: 100,
fps: 20,
record: true,
// // We init all our scene here
createScene: (THREE, sketch, globals) => {
const scene = new THREE.Scene()
scene.fog = new THREE.FogExp2(0x1E2630, 0.01)

// Lights
const light1 = new THREE.DirectionalLight('red')
light1.position.set(5, 0, 5)
light1.castShadow = true
scene.add(light1)
const light2 = new THREE.DirectionalLight('blue')
light2.position.set(5, 0, 5)
light2.castShadow = true
scene.add(light2)
const ambient = new THREE.AmbientLight('#ccc')
scene.add(ambient)

// Mesh
const geometry = new THREE.TorusGeometry(40, 10, 400, 1000)
geometry.setAttribute('uv2', new THREE.BufferAttribute(geometry.attributes.uv.array, 2))
const material = new THREE.MeshStandardMaterial({ side: THREE.BackSide })
const mesh = new THREE.Mesh(geometry, material)
mesh.receiveShadow = true
scene.add(mesh)
mesh.rotation.x = Math.PI/2
// loading textures
const wantedTextures = [colorURL, aoURL, normalURL, roughnessURL, heightURL].length
let texturesLoaded = 0
// Set `globals.isReady` to false to prevent the loop to start
// until all textures are loaded
globals.isReady = false
const onLoad = () => {
texturesLoaded ++
if(texturesLoaded === wantedTextures) globals.isReady = true
}
const textureLoader = new THREE.TextureLoader()

const repetition = new THREE.Vector2(5, 2)
const colorTexture = textureLoader.load(colorURL, onLoad)
colorTexture.repeat = repetition
colorTexture.wrapS = colorTexture.wrapT = THREE.RepeatWrapping
material.map = colorTexture
const aoTexture = textureLoader.load(aoURL, onLoad)
mesh.geometry.setAttribute('uv2', new THREE.BufferAttribute(mesh.geometry.attributes.uv.array, 2))
aoTexture.repeat = repetition
aoTexture.wrapS = aoTexture.wrapT = THREE.RepeatWrapping
aoTexture.colorSpace = THREE.SRGBColorSpace
material.aoMap = aoTexture
material.aoMapIntensity = 2
const normalTexture = textureLoader.load(normalURL, onLoad)
normalTexture.repeat = repetition
normalTexture.wrapS = normalTexture.wrapT = THREE.RepeatWrapping
normalTexture.colorSpace = THREE.SRGBColorSpace
material.normalMap = normalTexture
const roughnessTexture = textureLoader.load(roughnessURL, onLoad)
roughnessTexture.repeat = repetition
roughnessTexture.wrapS = roughnessTexture.wrapT = THREE.RepeatWrapping
roughnessTexture.colorSpace = THREE.SRGBColorSpace
material.roughnessMap = roughnessTexture
const heightTexture = textureLoader.load(heightURL, onLoad)
heightTexture.repeat = repetition
heightTexture.wrapS = heightTexture.wrapT = THREE.RepeatWrapping
heightTexture.colorSpace = THREE.SRGBColorSpace
material.displacementMap = heightTexture
material.displacementScale = 5

const camera = new THREE.PerspectiveCamera(75, globals.w / globals.h, 0.001, 1000)
camera.position.x = 39
camera.position.z = 30

const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setSize(globals.w, globals.h)
// createScene must return a function to update the scene
return (s, t, g) => {
const angle = t * s.TAU
// mesh.rotation.y = angle
mesh.rotation.z = angle
camera.position.y = Math.sin(angle)
light1.position.x = Math.cos(angle) * 5
light2.position.x = Math.cos(angle + Math.PI) * 5

renderer.render(scene, camera)
// the update function must return the renderer
return renderer
}
}
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
bnbThree = options => {
return bnb({
...options,

preload: (s, g) => {
if(options.preload) options.preload(s, g)
g.updateScene = options.createScene(THREE, s, g)

g.pg = s.createGraphics(g.w, g.h)
g.pg.pixelDensity(1)
g.data = new Uint8Array(g.w * g.h * 4)
g.imageData = g.pg.drawingContext.createImageData(g.w, g.h)
},

setup: (s, g) => {
if(options.setup) options.setup(s, g)
},

draw: (s, t, g) => {
if(options.draw) options.draw(s, t, g)
const gl = g.updateScene(s, t, g).getContext()

gl.readPixels(0, 0, g.w, g.h, gl.RGBA, gl.UNSIGNED_BYTE, g.data)
g.imageData.data.set(g.data)
g.pg.drawingContext.putImageData(g.imageData, 0, 0)

s.translate(0, g.h)
s.scale(1, -1)
s.image(g.pg, 0, 0, g.w, g.h)
}
})
}
Insert cell
Insert cell
Insert cell
THREE = import('https://unpkg.com/three/build/three.module.js?module')
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more