2023-11-30 16:19:45 +03:00
|
|
|
import * as THREE from 'three';
|
2023-11-30 19:31:13 +03:00
|
|
|
import { SpiralSegment } from './spiral.js';
|
2023-12-05 03:17:38 +03:00
|
|
|
import { SpiralCamera } from './controls.js';
|
|
|
|
import { TextGeometry } from 'three/addons/geometries/TextGeometry.js';
|
|
|
|
import { FontLoader } from 'three/addons/loaders/FontLoader.js';
|
2023-11-30 16:19:45 +03:00
|
|
|
|
|
|
|
|
2024-02-02 01:31:36 +03:00
|
|
|
|
2024-01-29 00:57:46 +03:00
|
|
|
const spiralMaterial = new THREE.ShaderMaterial( {
|
|
|
|
|
|
|
|
uniforms: {
|
|
|
|
time: { value: 1.0 },
|
|
|
|
resolution: { value: new THREE.Vector2() },
|
|
|
|
position: new THREE.Vector3()
|
|
|
|
},
|
|
|
|
|
2024-02-01 22:16:13 +03:00
|
|
|
// vertexShader: document.getElementById( 'vertexShader' ).textContent,
|
|
|
|
// fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
|
|
|
|
vertexShader: `
|
|
|
|
const float PI = 3.14159;
|
|
|
|
|
|
|
|
varying vec4 v_color;
|
|
|
|
varying float deg;
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
deg = degrees(atan(position.z, position.x)) ;
|
|
|
|
if (deg <= 0.) deg = 360. + deg;
|
|
|
|
|
|
|
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(position.x, position.y, position.z, 1.0);
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
fragmentShader: `
|
|
|
|
const float PI = 3.14159;
|
|
|
|
|
|
|
|
varying vec4 v_color;
|
|
|
|
varying float deg;
|
|
|
|
varying float toDiscard;
|
|
|
|
|
|
|
|
vec4 colors[12] = vec4[12](
|
|
|
|
vec4(0.202, 0.2406, 0.5922, 1), // jan
|
|
|
|
vec4(0.0980, 0.4627, 0.8235, 1), // feb
|
|
|
|
vec4(0.3984, 0.7305, 0.4141, 1), // mar
|
|
|
|
vec4(0.2188, 0.5547, 0.2344, 1), // apr
|
|
|
|
vec4(27./256., 94./256., 32./256., 1), // may
|
|
|
|
vec4(205./256., 220./256., 57./256., 1), // jun
|
|
|
|
vec4(255./256., 238./256., 88./256., 1), // jul
|
|
|
|
vec4(251./256., 192./256., 45./256., 1), // aug
|
|
|
|
vec4(255./256., 160./256., 0, 1), // sep
|
|
|
|
vec4(245./256., 124./256., 0, 1), // oct
|
|
|
|
vec4(230./256., 74./256., 25./256., 1), // nov
|
|
|
|
vec4(144./256., 164./256., 174./256., 1) // dec
|
|
|
|
);
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
if (int(round(deg)) % 30 == 0) discard;
|
|
|
|
|
|
|
|
int month = int((deg / 30.));
|
|
|
|
vec4 color = mix(colors[month], colors[month + 1], (deg - float(month) * 30.) / 30.);
|
|
|
|
|
|
|
|
gl_FragColor = color;
|
|
|
|
}
|
|
|
|
`
|
2024-01-29 00:57:46 +03:00
|
|
|
|
|
|
|
} );
|
2023-11-30 16:19:45 +03:00
|
|
|
|
2024-02-01 22:16:13 +03:00
|
|
|
const segmentHeight = 2;
|
|
|
|
|
|
|
|
let segments = [];
|
|
|
|
let viewingYear = new Date().getFullYear();
|
|
|
|
let viewDistance = 5;
|
|
|
|
|
|
|
|
//setting scene
|
2023-11-30 16:19:45 +03:00
|
|
|
const scene = new THREE.Scene();
|
|
|
|
|
2024-02-02 01:31:36 +03:00
|
|
|
const loader = new THREE.TextureLoader();
|
|
|
|
const texture = loader.load(
|
|
|
|
'view/img/space.jpg',
|
|
|
|
() => {
|
|
|
|
texture.mapping = THREE.EquirectangularReflectionMapping;
|
|
|
|
texture.colorSpace = THREE.SRGBColorSpace;
|
|
|
|
scene.background = texture;
|
|
|
|
});
|
|
|
|
|
2024-02-01 22:16:13 +03:00
|
|
|
//setting canvas
|
2023-11-30 16:19:45 +03:00
|
|
|
var canvas = document.querySelector('#canvas');
|
|
|
|
const renderer = new THREE.WebGLRenderer({ antialias: true, canvas });
|
2023-12-05 03:17:38 +03:00
|
|
|
document.body.appendChild(renderer.domElement);
|
2023-11-30 16:19:45 +03:00
|
|
|
|
2024-02-01 22:16:13 +03:00
|
|
|
//setting camera
|
2023-12-05 03:17:38 +03:00
|
|
|
const camera = (new SpiralCamera(canvas, segmentHeight));
|
2023-11-30 16:19:45 +03:00
|
|
|
|
|
|
|
// setting light
|
2023-12-05 03:17:38 +03:00
|
|
|
const pointLight = new THREE.PointLight(0xffffff, 1);
|
|
|
|
pointLight.position.set(0, 0, 1);
|
2023-11-30 16:19:45 +03:00
|
|
|
|
|
|
|
const ambientLight = new THREE.AmbientLight(0xffffff, 10);
|
|
|
|
|
|
|
|
scene.add(pointLight);
|
|
|
|
scene.add(ambientLight);
|
|
|
|
|
2024-02-01 22:16:13 +03:00
|
|
|
//Creating first segments
|
2023-12-05 03:17:38 +03:00
|
|
|
for (let i = 0; i < viewDistance * 2 + 1; i++) {
|
2024-02-01 22:16:13 +03:00
|
|
|
segments.push(new SpiralSegment(viewingYear - viewDistance + i, segmentHeight, spiralMaterial));
|
2023-12-05 03:17:38 +03:00
|
|
|
scene.add(segments[i].getSegment());
|
2023-12-07 12:56:12 +03:00
|
|
|
scene.add(segments[i].getText());
|
2024-02-01 22:16:13 +03:00
|
|
|
};
|
2024-01-24 20:03:41 +03:00
|
|
|
|
2023-12-05 03:17:38 +03:00
|
|
|
addEventListener("changedViewYear", (e) => {
|
|
|
|
let newYear = camera.getViewingYear();
|
|
|
|
|
|
|
|
if (newYear > viewingYear) { // +
|
|
|
|
scene.remove(segments[0].getSegment())
|
2023-12-07 12:56:12 +03:00
|
|
|
scene.remove(segments[0].getText())
|
2024-01-24 20:03:41 +03:00
|
|
|
|
|
|
|
segments.shift();
|
2024-02-01 22:16:13 +03:00
|
|
|
segments.push(new SpiralSegment(newYear + viewDistance, segmentHeight, spiralMaterial));
|
2024-01-24 20:03:41 +03:00
|
|
|
|
2023-12-05 03:17:38 +03:00
|
|
|
scene.add(segments[segments.length - 1].getSegment());
|
2023-12-07 12:56:12 +03:00
|
|
|
scene.add(segments[segments.length - 1].getText());
|
2024-02-01 22:16:13 +03:00
|
|
|
} else { // -
|
2023-12-05 03:17:38 +03:00
|
|
|
scene.remove(segments[segments.length - 1].getSegment())
|
2023-12-07 12:56:12 +03:00
|
|
|
scene.remove(segments[segments.length - 1].getText())
|
2024-01-24 20:03:41 +03:00
|
|
|
|
2023-12-05 03:17:38 +03:00
|
|
|
segments.pop();
|
2024-02-01 22:16:13 +03:00
|
|
|
segments.unshift(new SpiralSegment(newYear - viewDistance, segmentHeight, spiralMaterial))
|
2024-01-29 00:57:46 +03:00
|
|
|
|
2023-12-05 03:17:38 +03:00
|
|
|
scene.add(segments[0].getSegment());
|
2023-12-07 12:56:12 +03:00
|
|
|
scene.add(segments[0].getText());
|
2023-12-05 03:17:38 +03:00
|
|
|
}
|
2023-12-01 12:57:41 +03:00
|
|
|
|
2023-12-05 03:17:38 +03:00
|
|
|
viewingYear = newYear;
|
|
|
|
});
|
2023-12-01 12:57:41 +03:00
|
|
|
|
2024-02-02 01:31:36 +03:00
|
|
|
|
2023-11-30 16:19:45 +03:00
|
|
|
//main loop
|
|
|
|
function animate() {
|
|
|
|
if (resizeRendererToDisplaySize(renderer)) {
|
|
|
|
const canvas = renderer.domElement;
|
2023-12-05 03:17:38 +03:00
|
|
|
camera.getCamera().aspect = canvas.clientWidth / canvas.clientHeight;
|
|
|
|
camera.getCamera().updateProjectionMatrix();
|
2023-11-30 16:19:45 +03:00
|
|
|
}
|
|
|
|
|
2024-02-01 22:16:13 +03:00
|
|
|
// moving text along with the camera and spiral
|
2023-12-05 03:17:38 +03:00
|
|
|
for (let i = 0; i < segments.length; i++) {
|
|
|
|
segments[i].getSegment().position.y = ((segments[i].year - camera.getViewingYear()) * segmentHeight + camera.getOffset());
|
2023-12-07 12:56:12 +03:00
|
|
|
segments[i].getText().position.y = segmentHeight / 2 +(segments[i].year - camera.getViewingYear()) * segmentHeight + camera.getOffset();
|
2024-01-24 20:03:41 +03:00
|
|
|
segments[i].getText().position.x = 2.5*Math.cos(THREE.MathUtils.degToRad(camera.getAngle() + 90)) * 3
|
|
|
|
segments[i].getText().position.z = 2.5*Math.sin(THREE.MathUtils.degToRad(camera.getAngle() + 90)) * 3
|
2023-12-07 12:56:12 +03:00
|
|
|
segments[i].getText().lookAt(camera.getCamera().position)
|
2023-12-05 03:17:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
camera.getCamera().lookAt(0, 0, 0);
|
2023-12-01 12:57:41 +03:00
|
|
|
|
2023-12-05 03:17:38 +03:00
|
|
|
renderer.render(scene, camera.getCamera());
|
2023-11-30 16:19:45 +03:00
|
|
|
|
|
|
|
requestAnimationFrame(animate);
|
|
|
|
}
|
|
|
|
|
|
|
|
function resizeRendererToDisplaySize(renderer) {
|
|
|
|
const canvas = renderer.domElement;
|
|
|
|
const width = canvas.clientWidth;
|
|
|
|
const height = canvas.clientHeight;
|
|
|
|
|
|
|
|
const needResize = canvas.width !== width || canvas.height !== height;
|
|
|
|
if (needResize) renderer.setSize(width, height, false);
|
|
|
|
|
|
|
|
return needResize;
|
|
|
|
}
|
|
|
|
|
|
|
|
animate();
|