Public
Edited
Mar 25, 2024
Importers
22 stars
Also listed in…
threejs loops
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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more