Published
Edited
Dec 5, 2018
10 stars
Insert cell
Insert cell
Insert cell
Insert cell
function setup() {
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(45, width / height, 1, 1000)
const renderer = new THREE.WebGLRenderer({ antialias: true })
const controls = new THREE.OrbitControls(camera, renderer.domElement);
// set renderer size
renderer.setSize(width, height)
// set camera position
camera.position.set( 0, 0, 100 )
camera.lookAt( 0, 0, 0 )
controls.addEventListener("change", () => renderer.render(scene, camera));
return {scene, camera, renderer}
}
Insert cell
{
// set up scene, camera, and renderer
const {scene, camera, renderer} = setup()
// Geometry parameters
const sides = 4;
const height = 40;
const capHeight = 5;
const heightSegments = 3;
const radius = 10;

// The middle part of the crystal, with open-ended top and bottom faces
const middle = new THREE.CylinderGeometry(radius, radius, height, sides, heightSegments, true);

// Create an open-ended cone
const coneTop = new THREE.ConeGeometry(radius, capHeight, sides, heightSegments, true);
// Clone it so we have two different geometries (one for each end)
const coneBottom = coneTop.clone();

// Move the top cap up to the correct place
coneTop.translate(0, height / 2 + capHeight / 2, 0);
// First flip the bottom cap, then move it down
coneBottom.rotateZ(Math.PI);
coneBottom.translate(0, -height / 2 - capHeight / 2, 0);
// Now construct our final geometry
const geometry = new THREE.Geometry();
geometry.merge(middle);
geometry.merge(coneTop);
geometry.merge(coneBottom);
// Notice I am using flat shading in the material, to give it a faceted look.
// Most ThreeJS geometries will appear smooth by default.
const material = new THREE.MeshNormalMaterial({ flatShading: true });
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh);
// Now let's store a copy of all the 'original' vertices of our geometry
// before we go messing them up!
const originalVertices = geometry.vertices.map(v => v.clone());

// We can use ThreeJS clock to get time per frame
const clock = new THREE.Clock();
while (true) {
// Get the current time in seconds
const time = clock.getElapsedTime();
// Rotate our mesh by the time
mesh.rotation.y = time * 0.25;

// Now let's mess up each vertex
geometry.vertices.forEach((vertex, i) => {
// Get the original vertices that make up the 'perfect' (i.e. un-messed-up) geometry
const original = originalVertices[i];

// Reset the vertex to its original/initial state so we can mess it up by time
vertex.copy(original);
// Now you can modify the XYZ components, rotate, scale, skew, or whatever !
vertex.applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.sin(original.y * 2 + time * 2) * 1);
});
// Before rendering, we need to flag the geometry as "needing an update"
// i.e. this will send the new vertices to the GPU so it can be rendered
// We only need to do this when we change vertices in a Geometry.
geometry.verticesNeedUpdate = true;
renderer.render(scene, camera);
yield renderer.domElement;
}
}
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