mirror of
https://github.com/Sheldan/canvas.git
synced 2026-05-21 14:35:06 +00:00
moving orbits to directory
This commit is contained in:
229
orbits/src/js/main.js
Normal file
229
orbits/src/js/main.js
Normal file
@@ -0,0 +1,229 @@
|
||||
import * as THREE from 'three';
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
||||
import {TextGeometry} from 'three/addons/geometries/TextGeometry.js'
|
||||
import Stats from 'three/addons/libs/stats.module.js';
|
||||
import createSpheres from './setup'
|
||||
import spheresAct from './physics'
|
||||
import {FontLoader} from "three/addons";
|
||||
|
||||
const loader = new FontLoader();
|
||||
|
||||
|
||||
const config = {
|
||||
gravitationalConstant: 6.67430e-11,
|
||||
timeStep: 1 * 3600,
|
||||
AU: 149_597_870_700,
|
||||
pause: false,
|
||||
lines: true,
|
||||
currentTime: 1710633600 // Sun Mar 17 2024 00:00:00 GMT+0000
|
||||
}
|
||||
|
||||
const maxPoints = 50_000;
|
||||
const scene = new THREE.Scene();
|
||||
const container = document.getElementById( 'container' );
|
||||
const currentTimeSpan = document.getElementById( 'currentTime' );
|
||||
const renderer = new THREE.WebGLRenderer({ antialias: true, logarithmicDepthBuffer: true });
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
renderer.setSize(container.offsetWidth, container.offsetHeight);
|
||||
container.appendChild(renderer.domElement);
|
||||
const stats = new Stats();
|
||||
container.appendChild( stats.dom );
|
||||
const camera = new THREE.PerspectiveCamera( 45, container.offsetWidth / container.offsetHeight, 1, 150 * config.AU);
|
||||
|
||||
const controls = new OrbitControls(camera, renderer.domElement);
|
||||
const texts = [];
|
||||
let lines = {}
|
||||
|
||||
let axesHelper;
|
||||
const spheres = createSpheres();
|
||||
const initialSpheres = JSON.parse(JSON.stringify(spheres));
|
||||
loader.load(
|
||||
// resource URL
|
||||
"https://threejs.org/examples/fonts/helvetiker_regular.typeface.json", function(font) {
|
||||
initScene(font);
|
||||
animate()
|
||||
})
|
||||
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame( animate );
|
||||
controls.update();
|
||||
stats.update();
|
||||
render();
|
||||
}
|
||||
|
||||
function reset() {
|
||||
config.currentTime = 1710633600;
|
||||
spheres.spheres.forEach(sphereConfig => {
|
||||
sphereConfig.line.material.dispose();
|
||||
sphereConfig.line.geometry.dispose();
|
||||
sphereConfig.group.remove(sphereConfig.line)
|
||||
scene.remove(sphereConfig.line)
|
||||
const oldSphere = initialSpheres.spheres.find((sphere => sphere.name === sphereConfig.name))
|
||||
sphereConfig.x = oldSphere.x;
|
||||
sphereConfig.y = oldSphere.y;
|
||||
sphereConfig.z = oldSphere.z;
|
||||
sphereConfig.vx = oldSphere.vx;
|
||||
sphereConfig.vy = oldSphere.vy;
|
||||
sphereConfig.vz = oldSphere.vz;
|
||||
sphereConfig.group.position.x = sphereConfig.x;
|
||||
sphereConfig.group.position.y = sphereConfig.y;
|
||||
sphereConfig.group.position.z = sphereConfig.z;
|
||||
const textMesh = sphereConfig.text;
|
||||
const labelLine = [];
|
||||
labelLine.push(new THREE.Vector3(textMesh.position.x, textMesh.position.y, textMesh.position.z));
|
||||
labelLine.push(new THREE.Vector3(0, 0, 0 ));
|
||||
const lineMaterial = new THREE.LineBasicMaterial({color: sphereConfig.sphereColor});
|
||||
const lineGeometry = new THREE.BufferGeometry().setFromPoints(labelLine);
|
||||
sphereConfig.line = new THREE.Line( lineGeometry, lineMaterial);;
|
||||
sphereConfig.group.add(sphereConfig.line);
|
||||
lines = {}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function render() {
|
||||
act()
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
function formatDateTime(input) {
|
||||
var epoch = new Date(0);
|
||||
epoch.setSeconds(parseInt(input));
|
||||
var date = epoch.toISOString();
|
||||
date = date.replace('T', ' ');
|
||||
return date.split('.')[0].split(' ')[0];
|
||||
}
|
||||
|
||||
|
||||
function act() {
|
||||
axesHelper.position.copy(controls.target);
|
||||
texts.forEach(text => {
|
||||
text.lookAt(camera.position)
|
||||
})
|
||||
if(config.pause) {
|
||||
return;
|
||||
}
|
||||
spheresAct(spheres.spheres, config.timeStep)
|
||||
config.currentTime += config.timeStep;
|
||||
currentTimeSpan.innerText = formatDateTime(config.currentTime)
|
||||
if(config.lines) {
|
||||
spheres.spheres.forEach(sphere => {
|
||||
if(!(sphere.name in lines)) {
|
||||
lines[sphere.name] = []
|
||||
const positions = new Float32Array(maxPoints * 3); // 3 vertices per point
|
||||
const geometry = new THREE.BufferGeometry();
|
||||
geometry.setDrawRange(0, 0);
|
||||
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
|
||||
const material = new THREE.LineBasicMaterial( { color: getSphereColor(sphere) } );
|
||||
const line = new THREE.Line(geometry, material);
|
||||
scene.add(line);
|
||||
sphere.line = line;
|
||||
}
|
||||
const pos = {
|
||||
x: sphere.x,
|
||||
y: sphere.y,
|
||||
z: sphere.z
|
||||
}
|
||||
const positionAttribute = sphere.line.geometry.getAttribute( 'position' );
|
||||
lines[sphere.name].push(pos);
|
||||
let currentLength = lines[sphere.name].length - 1;
|
||||
positionAttribute.setXYZ(currentLength, sphere.x, sphere.y, sphere.z);
|
||||
sphere.line.geometry.setDrawRange(0, currentLength);
|
||||
positionAttribute.needsUpdate = true;
|
||||
})
|
||||
}
|
||||
spheres.spheres.forEach(sphere => {
|
||||
sphere.group.position.x = sphere.x;
|
||||
sphere.group.position.y = sphere.y;
|
||||
sphere.group.position.z = sphere.z;
|
||||
})
|
||||
}
|
||||
|
||||
function getSphereColor(sphereConfig) {
|
||||
return new THREE.Color(sphereConfig.color.r / 255, sphereConfig.color.g / 255, sphereConfig.color.b / 255);
|
||||
}
|
||||
|
||||
function resetControls() {
|
||||
const sun = spheres.sphereObj.sun;
|
||||
camera.position.set(sun.x, sun.y, sun.z + config.AU)
|
||||
camera.lookAt(sun.x, sun.y, sun.z)
|
||||
controls.target.set(sun.x, sun.y, sun.z)
|
||||
controls.update();
|
||||
axesHelper.position.copy(controls.target);
|
||||
}
|
||||
|
||||
function initScene(font) {
|
||||
const geometry = new THREE.SphereGeometry(0.5, 24, 12);
|
||||
let scale = config.AU / 10;
|
||||
spheres.spheres.forEach(sphereConfig => {
|
||||
|
||||
let sphereColor = getSphereColor(sphereConfig);
|
||||
const material = new THREE.MeshBasicMaterial({color: sphereColor});
|
||||
|
||||
const sphere = new THREE.Mesh(geometry, material);
|
||||
const group = new THREE.Group();
|
||||
group.position.x = sphereConfig.x;
|
||||
group.position.y = sphereConfig.y;
|
||||
group.position.z = sphereConfig.z;
|
||||
let objectRadius = Math.log(sphereConfig.radius) * 100000000 / 5;
|
||||
sphere.scale.multiplyScalar(objectRadius)
|
||||
group.add(sphere);
|
||||
|
||||
const label = new TextGeometry(sphereConfig.name, {
|
||||
size: 0.25,
|
||||
font: font,
|
||||
height: 0.25
|
||||
});
|
||||
|
||||
let textDistance = 2;
|
||||
if (sphereConfig.isMoon) {
|
||||
textDistance = 5;
|
||||
}
|
||||
const textMesh = new THREE.Mesh(label, material);
|
||||
textMesh.scale.set( scale, scale, scale );
|
||||
textMesh.position.x = textDistance * objectRadius * (Math.random() * textDistance - textDistance) + Math.random() * config.AU / 10;
|
||||
textMesh.position.y = textDistance * objectRadius * (Math.random() * textDistance - textDistance) + Math.random() * config.AU / 10;
|
||||
texts.push(textMesh)
|
||||
group.add(textMesh);
|
||||
sphereConfig.text = textMesh;
|
||||
sphereConfig.group = group;
|
||||
sphereConfig.sphereColor = sphereColor;
|
||||
|
||||
const labelLine = [];
|
||||
labelLine.push(new THREE.Vector3(textMesh.position.x, textMesh.position.y, textMesh.position.z));
|
||||
labelLine.push(new THREE.Vector3(0, 0, 0 ));
|
||||
const lineMaterial = new THREE.LineBasicMaterial({color: sphereColor});
|
||||
const lineGeometry = new THREE.BufferGeometry().setFromPoints(labelLine);
|
||||
const line = new THREE.Line( lineGeometry, lineMaterial);
|
||||
sphereConfig.line = line;
|
||||
group.add(line);
|
||||
scene.add(group);
|
||||
})
|
||||
|
||||
scene.add(new THREE.AmbientLight( 0x777777 ) );
|
||||
|
||||
const light = new THREE.DirectionalLight( 0xffffff, 3 );
|
||||
const sun = spheres.sphereObj.sun
|
||||
light.position.set(sun.x, sun.y, sun.z);
|
||||
scene.add(light);
|
||||
scene.position.set(sun.x, sun.y, sun.z)
|
||||
axesHelper = new THREE.AxesHelper(config.AU / 5);
|
||||
resetControls();
|
||||
scene.add(axesHelper)
|
||||
}
|
||||
|
||||
function keyPress(event) {
|
||||
let keyCode = event.which;
|
||||
if(keyCode === 82) {
|
||||
reset()
|
||||
} else if(keyCode === 70) {
|
||||
resetControls()
|
||||
} else if(keyCode === 80) {
|
||||
config.pause = !config.pause;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", keyPress, false);
|
||||
|
||||
|
||||
57
orbits/src/js/physics.js
Normal file
57
orbits/src/js/physics.js
Normal file
@@ -0,0 +1,57 @@
|
||||
const config = {
|
||||
gravitationalConstant: 6.67428e-11
|
||||
}
|
||||
|
||||
function attraction(sphere1, sphere2) {
|
||||
const dx = sphere1.x - sphere2.x;
|
||||
const dy = sphere1.y - sphere2.y;
|
||||
const dz = sphere1.z - sphere2.z;
|
||||
const direction = {
|
||||
dx: sphere1.x - sphere2.x,
|
||||
dy : sphere1.y - sphere2.y,
|
||||
dz : sphere1.z - sphere2.z
|
||||
};
|
||||
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
if (dist === 0) {
|
||||
return;
|
||||
}
|
||||
const force = config.gravitationalConstant * sphere2.mass * sphere1.mass / (dist * dist * dist);
|
||||
return {fx: direction.dx * force, fy: direction.dy * force, fz: direction.dz * force}
|
||||
}
|
||||
|
||||
function sphereAct(spheres, sphere, parentIndex) {
|
||||
let totalForce = {
|
||||
fx: 0, fy: 0, fz: 0
|
||||
};
|
||||
for (let sphereI = 0; sphereI < spheres.length; sphereI++) {
|
||||
if (sphereI === parentIndex) {
|
||||
continue;
|
||||
}
|
||||
let forces = attraction(spheres[sphereI], sphere);
|
||||
if (forces) {
|
||||
totalForce.fx += forces.fx;
|
||||
totalForce.fy += forces.fy;
|
||||
totalForce.fz += forces.fz;
|
||||
}
|
||||
}
|
||||
sphere.force = totalForce;
|
||||
}
|
||||
|
||||
function spheresAct(spheres, step) {
|
||||
for (let sphereI = 0; sphereI < spheres.length; sphereI++) {
|
||||
sphereAct(spheres, spheres[sphereI], sphereI);
|
||||
}
|
||||
for (let sphere2I = 0; sphere2I < spheres.length; sphere2I++) {
|
||||
const sphere = spheres[sphere2I];
|
||||
sphere.vx += sphere.force.fx / sphere.mass * step;
|
||||
sphere.vy += sphere.force.fy / sphere.mass * step;
|
||||
sphere.vz += sphere.force.fz / sphere.mass * step;
|
||||
|
||||
sphere.x += sphere.vx * step;
|
||||
sphere.y += sphere.vy * step;
|
||||
sphere.z += sphere.vz * step;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default spheresAct
|
||||
1025
orbits/src/js/setup.js
Normal file
1025
orbits/src/js/setup.js
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user