<form id="buttons">
<fieldset>
<legend>Focus and zoom to target</legend>
<button type="button">Sphere 1</button>
<button type="button">Sphere 2</button>
<button type="button">Sphere 3</button>
<button type="button">Sphere 4</button>
<button type="button">Sphere 5 - Line Vibrates</button>
<button type="button">Sphere 6 - Line Vibrates</button>
</fieldset>
</form>
html, body {
margin: 0;
padding: 0;
border: 0;
overflow: hidden;
font-family: sans-serif;
}
body {
position: relative;
}
#buttons {
color: #FFF;
position: absolute;
top: 10px;
left: 10px;
}
import * as THREE from 'https://cdn.skypack.dev/three@0.132.0/build/three.module.js'
import CameraControls from "https://cdn.skypack.dev/camera-controls@1.36.0";
const scene = new THREE.Scene();
const clock = new THREE.Clock();
const maxDistance = 100000000000;
const camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, maxDistance );
const renderer = new THREE.WebGLRenderer({
logarithmicDepthBuffer: true,
antialias: true
});
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
const sphere = new THREE.Mesh(
new THREE.SphereBufferGeometry( 100, 100, 100 ),
new THREE.MeshBasicMaterial({
color: new THREE.Color('white')
})
);
scene.add( sphere );
camera.position.z = 1000;
CameraControls.install( { THREE: THREE } );
const controls = new CameraControls(camera, renderer.domElement);
controls.maxDistance = maxDistance;
// ///////////
// SKYBOX
// ///////////
const textureLoader = new THREE.TextureLoader(THREE.DefaultLoadingManager);
const spaceImages = {
spaceFt: 'https://i.imgur.com/rU5MD9T.jpg',
spaceBk: 'https://i.imgur.com/naP6ygJ.jpg',
spaceUp: 'https://i.imgur.com/NpI2TqZ.jpg',
spaceDn: 'https://i.imgur.com/gGpcZ0S.jpg',
spaceRt: 'https://i.imgur.com/RAyAyiS.jpg',
spaceLt: 'https://i.imgur.com/aprdPTY.jpg'
};
const skyboxTexturePaths = Object.values(spaceImages);
const skybox = (texturePaths) => {
const skyboxMaterialArray = texturePaths.map(
(image) => new THREE.MeshBasicMaterial({ map: textureLoader.load(image), side: THREE.BackSide })
);
const skybox = new THREE.Mesh(
new THREE.BoxBufferGeometry(1000000000000, 1000000000000, 1000000000000),
skyboxMaterialArray
);
skybox.name = 'skybox';
return skybox;
};
scene.add(skybox(skyboxTexturePaths));
// ///////////
// COLOUR LERP
// ///////////
const amountOfOrbitToDraw = 330 // out of 360
const generateColors = (startColor, geometryCount) => {
// how much fade we want, closer to 0 means fades earlier
const lerpAcc = 1;
const lerpIncrementer = 1 / amountOfOrbitToDraw / lerpAcc;
const colors = new Float32Array(geometryCount * 3);
for (let c = 0; c <= amountOfOrbitToDraw; c += 1) {
const lerpColor = new THREE.Color(startColor);
lerpColor.lerpColors(startColor, new THREE.Color('black'), c * lerpIncrementer);
colors[c * 3 + 0] = lerpColor.r;
colors[c * 3 + 1] = lerpColor.g;
colors[c * 3 + 2] = lerpColor.b;
}
return colors;
}
// ///////////
// ORBIT LINES
// ///////////
const createOrbitLine = (radius, color) => {
const points = [];
for (let i = 0; i <= amountOfOrbitToDraw; i++) {
const v = new THREE.Vector3(Math.sin(THREE.MathUtils.degToRad(i))*radius, 0, Math.cos(THREE.MathUtils.degToRad(i))*radius);
points.push(v);
}
const geometryLine = new THREE.BufferGeometry().setFromPoints(points);
geometryLine.setAttribute('color', new THREE.BufferAttribute(generateColors(new THREE.Color('white'), geometryLine.getAttribute('position').count), 3));
const material = new THREE.LineBasicMaterial({
transparent: true,
blending: THREE.AdditiveBlending,
vertexColors: true
});
const line = new THREE.Line(geometryLine, material)
return line;
}
const orbitLines = [
{
color: 'red',
radius: 10000
},
{
color: 'orange',
radius: 1000000
},
{
color: 'yellow',
radius: 10000000
},
{
color: 'green',
radius: 100000000
},
{
color: 'blue',
radius: 1000000000
},
{
color: 'purple',
radius: 10000000000
}
]
// ///////////
// ORBIT SPHERES
// ///////////
const orbitSpheres = [];
const orbitSphereSize = 1000;
orbitLines.forEach((orbitLine, i) => {
scene.add(createOrbitLine(orbitLine.radius, new THREE.Color(orbitLine.color)));
const orbitSphere = new THREE.Mesh(
new THREE.SphereBufferGeometry( orbitSphereSize, orbitSphereSize, 100 ),
new THREE.MeshBasicMaterial({
color: new THREE.Color(orbitLine.color),
transparent: true,
opacity: 0.8
})
);
orbitSphere.position.set(0, 0, orbitLine.radius);
scene.add(orbitSphere);
orbitSpheres.push(orbitSphere);
});
const focusOnTarget = (target) => {
controls.setLookAt(
target.position.x + (orbitSphereSize * 2), target.position.y, target.position.z + (orbitSphereSize * 2),
target.position.x, target.position.y, target.position.z,
true
)
}
// ///////////
// RENDER LOOP
// ///////////
(function animate() {
const delta = clock.getDelta();
const elapsed = clock.getElapsedTime();
const updated = controls.update( delta );
requestAnimationFrame( animate );
if (updated) {
renderer.render( scene, camera );
}
})();
[...document.querySelectorAll('#buttons button')].forEach((button, i) => {
button.addEventListener('click', () => {
focusOnTarget(orbitSpheres[i]);
})
});
document.addEventListener('DOMContentLoaded', () => {
// this seems to be needed, or else the initial load renders a black screen
renderer.render( scene, camera );
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.