Sonnensystem verbessert
This commit is contained in:
+215
-6
@@ -271,6 +271,7 @@ const AU_IN_KM = 149597870.7;
|
|||||||
const DISPLAY_SCALE = 34;
|
const DISPLAY_SCALE = 34;
|
||||||
const USER_MINOR_PLANETS = <?= json_encode($trackedMinorplanetsForJs, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
const USER_MINOR_PLANETS = <?= json_encode($trackedMinorplanetsForJs, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||||||
const JUPITER_MIN_VISIBLE_SIZE = 1.42;
|
const JUPITER_MIN_VISIBLE_SIZE = 1.42;
|
||||||
|
const MOON_DISPLAY_DISTANCE_MULTIPLIER = 2200;
|
||||||
|
|
||||||
const PLANETS = [
|
const PLANETS = [
|
||||||
{ key: 'Mercury', label: 'Merkur', color: '#aeb7c4', emissive: '#29303a', size: 0.34, type: 'Gesteinsplanet', roughness: 0.95, metalness: 0.00, glow: false, texture: 'images/planets/merkur_1024.jpg' },
|
{ key: 'Mercury', label: 'Merkur', color: '#aeb7c4', emissive: '#29303a', size: 0.34, type: 'Gesteinsplanet', roughness: 0.95, metalness: 0.00, glow: false, texture: 'images/planets/merkur_1024.jpg' },
|
||||||
@@ -283,6 +284,18 @@ const PLANETS = [
|
|||||||
{ key: 'Neptune', label: 'Neptun', color: '#4f78f0', emissive: '#101b46', size: 0.92, type: 'Eisriese', roughness: 0.92, metalness: 0.00, glow: true, texture: 'images/planets/neptun_1024.jpg' },
|
{ key: 'Neptune', label: 'Neptun', color: '#4f78f0', emissive: '#101b46', size: 0.92, type: 'Eisriese', roughness: 0.92, metalness: 0.00, glow: true, texture: 'images/planets/neptun_1024.jpg' },
|
||||||
{ key: 'Pluto', label: 'Pluto', color: '#c5b090', emissive: '#3c2f20', size: 0.26, type: 'Zwergplanet', roughness: 0.95, metalness: 0.00, glow: false, texture: 'images/planets/pluto_1024.jpg' }
|
{ key: 'Pluto', label: 'Pluto', color: '#c5b090', emissive: '#3c2f20', size: 0.26, type: 'Zwergplanet', roughness: 0.95, metalness: 0.00, glow: false, texture: 'images/planets/pluto_1024.jpg' }
|
||||||
];
|
];
|
||||||
|
const MOON = {
|
||||||
|
key: 'Moon',
|
||||||
|
label: 'Mond',
|
||||||
|
color: '#d7d7d7',
|
||||||
|
emissive: '#2d2d30',
|
||||||
|
size: 0.17,
|
||||||
|
type: 'Mond',
|
||||||
|
roughness: 0.96,
|
||||||
|
metalness: 0.00,
|
||||||
|
texture: 'images/moons/moon_1024.jpg',
|
||||||
|
orbitalPeriodDays: 27.321661,
|
||||||
|
};
|
||||||
|
|
||||||
const stageWrap = document.getElementById('solarStageWrap');
|
const stageWrap = document.getElementById('solarStageWrap');
|
||||||
const canvas = document.getElementById('solarCanvas');
|
const canvas = document.getElementById('solarCanvas');
|
||||||
@@ -320,6 +333,9 @@ let raycaster;
|
|||||||
let pointer;
|
let pointer;
|
||||||
let eclipticGroup;
|
let eclipticGroup;
|
||||||
let rotationEqjToEcl;
|
let rotationEqjToEcl;
|
||||||
|
let moonMesh = null;
|
||||||
|
let moonOrbitLine = null;
|
||||||
|
let moonLabelElement = null;
|
||||||
let minorPlanetOrbitLine = null;
|
let minorPlanetOrbitLine = null;
|
||||||
let minorPlanetMesh = null;
|
let minorPlanetMesh = null;
|
||||||
let minorPlanetLabelElement = null;
|
let minorPlanetLabelElement = null;
|
||||||
@@ -480,6 +496,75 @@ function toDisplayPosition(position) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toDisplayDirection(vector) {
|
||||||
|
return new THREE.Vector3(
|
||||||
|
vector.x,
|
||||||
|
vector.z,
|
||||||
|
-vector.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPlanetRotationState(key, date) {
|
||||||
|
try {
|
||||||
|
const axisInfo = AstronomyEngine.RotationAxis(getPlanetBodyKey(key), date);
|
||||||
|
if (!axisInfo || !axisInfo.north) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const northEqj = axisInfo.north;
|
||||||
|
const northEcl = rotationEqjToEcl
|
||||||
|
? AstronomyEngine.RotateVector(rotationEqjToEcl, northEqj)
|
||||||
|
: northEqj;
|
||||||
|
const northDisplay = toDisplayDirection(northEcl).normalize();
|
||||||
|
|
||||||
|
if (!Number.isFinite(northDisplay.lengthSq()) || northDisplay.lengthSq() < 1e-12) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
northDisplay,
|
||||||
|
spinRad: THREE.MathUtils.degToRad(Number(axisInfo.spin) || 0),
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMoonGeoPosition(date) {
|
||||||
|
const astroTime = AstronomyEngine.MakeTime(date);
|
||||||
|
const vectorEqj = AstronomyEngine.GeoVector('Moon', astroTime, true);
|
||||||
|
const vectorEcl = rotationEqjToEcl
|
||||||
|
? AstronomyEngine.RotateVector(rotationEqjToEcl, vectorEqj)
|
||||||
|
: vectorEqj;
|
||||||
|
const radiusAu = Math.hypot(vectorEcl.x, vectorEcl.y, vectorEcl.z);
|
||||||
|
return { x: vectorEcl.x, y: vectorEcl.y, z: vectorEcl.z, r: radiusAu };
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMoonHelioPosition(date) {
|
||||||
|
const earthPosition = getHelioPosition('Earth', date);
|
||||||
|
const moonGeoPosition = getMoonGeoPosition(date);
|
||||||
|
return {
|
||||||
|
x: earthPosition.x + moonGeoPosition.x,
|
||||||
|
y: earthPosition.y + moonGeoPosition.y,
|
||||||
|
z: earthPosition.z + moonGeoPosition.z,
|
||||||
|
r: Math.hypot(
|
||||||
|
earthPosition.x + moonGeoPosition.x,
|
||||||
|
earthPosition.y + moonGeoPosition.y,
|
||||||
|
earthPosition.z + moonGeoPosition.z
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMoonDisplayPosition(date) {
|
||||||
|
const earthHelioPosition = getHelioPosition('Earth', date);
|
||||||
|
const earthDisplayPosition = toDisplayPosition(earthHelioPosition);
|
||||||
|
const moonGeoPosition = getMoonGeoPosition(date);
|
||||||
|
const moonGeoDisplayOffset = toDisplayDirection(moonGeoPosition)
|
||||||
|
.multiplyScalar(MOON_DISPLAY_DISTANCE_MULTIPLIER);
|
||||||
|
|
||||||
|
return earthDisplayPosition.clone().add(moonGeoDisplayOffset);
|
||||||
|
}
|
||||||
|
|
||||||
function refreshCurrentDateUi() {
|
function refreshCurrentDateUi() {
|
||||||
currentDateLabel.textContent = formatDisplayDate(simDate);
|
currentDateLabel.textContent = formatDisplayDate(simDate);
|
||||||
datePicker.value = formatDateInput(simDate);
|
datePicker.value = formatDateInput(simDate);
|
||||||
@@ -608,6 +693,83 @@ function buildLabels() {
|
|||||||
labelsLayer.appendChild(label);
|
labelsLayer.appendChild(label);
|
||||||
labelElements.set(planet.key, label);
|
labelElements.set(planet.key, label);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
moonLabelElement = document.createElement('div');
|
||||||
|
moonLabelElement.className = 'solarsystem-planet-label';
|
||||||
|
moonLabelElement.textContent = MOON.label;
|
||||||
|
moonLabelElement.style.color = MOON.color;
|
||||||
|
moonLabelElement.hidden = true;
|
||||||
|
labelsLayer.appendChild(moonLabelElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureMoonObjects() {
|
||||||
|
if (moonMesh && moonOrbitLine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const moonTex = textureLoader.load(MOON.texture);
|
||||||
|
moonTex.colorSpace = THREE.SRGBColorSpace;
|
||||||
|
|
||||||
|
moonMesh = new THREE.Mesh(
|
||||||
|
new THREE.SphereGeometry(MOON.size, 28, 28),
|
||||||
|
new THREE.MeshStandardMaterial({
|
||||||
|
color: 0xffffff,
|
||||||
|
map: moonTex,
|
||||||
|
emissive: new THREE.Color(MOON.emissive),
|
||||||
|
emissiveIntensity: 0.05,
|
||||||
|
roughness: MOON.roughness,
|
||||||
|
metalness: MOON.metalness,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
moonMesh.castShadow = true;
|
||||||
|
moonMesh.receiveShadow = true;
|
||||||
|
moonMesh.userData.baseScale = 1;
|
||||||
|
moonMesh.userData.minScaleMultiplier = 1;
|
||||||
|
scene.add(moonMesh);
|
||||||
|
|
||||||
|
moonOrbitLine = new THREE.Line(
|
||||||
|
new THREE.BufferGeometry(),
|
||||||
|
new THREE.LineBasicMaterial({
|
||||||
|
color: new THREE.Color(MOON.color),
|
||||||
|
transparent: true,
|
||||||
|
opacity: 0.55,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
moonOrbitLine.visible = showOrbits;
|
||||||
|
scene.add(moonOrbitLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rebuildMoonOrbitLine() {
|
||||||
|
ensureMoonObjects();
|
||||||
|
|
||||||
|
const positions = [];
|
||||||
|
const steps = 180;
|
||||||
|
for (let step = 0; step <= steps; step += 1) {
|
||||||
|
const offsetDays = (step / steps) * MOON.orbitalPeriodDays;
|
||||||
|
const date = new Date(simDate.getTime() + offsetDays * 86400000);
|
||||||
|
const display = getMoonDisplayPosition(date);
|
||||||
|
positions.push(display.x, display.y, display.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
moonOrbitLine.geometry.dispose();
|
||||||
|
moonOrbitLine.geometry = new THREE.BufferGeometry();
|
||||||
|
moonOrbitLine.geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
|
||||||
|
moonOrbitLine.visible = showOrbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMoonVisual() {
|
||||||
|
ensureMoonObjects();
|
||||||
|
|
||||||
|
const display = getMoonDisplayPosition(simDate);
|
||||||
|
moonMesh.position.copy(display);
|
||||||
|
|
||||||
|
const rotationState = getPlanetRotationState('Moon', simDate);
|
||||||
|
if (rotationState) {
|
||||||
|
moonMesh.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), rotationState.northDisplay);
|
||||||
|
moonMesh.rotateY(rotationState.spinRad);
|
||||||
|
}
|
||||||
|
|
||||||
|
moonOrbitLine.visible = showOrbits;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensureMinorPlanetObjects() {
|
function ensureMinorPlanetObjects() {
|
||||||
@@ -783,7 +945,7 @@ function updateMinorPlanetVisual() {
|
|||||||
const display = toDisplayPosition(heliocentric);
|
const display = toDisplayPosition(heliocentric);
|
||||||
minorPlanetMesh.visible = true;
|
minorPlanetMesh.visible = true;
|
||||||
minorPlanetMesh.position.copy(display);
|
minorPlanetMesh.position.copy(display);
|
||||||
minorPlanetMesh.rotation.y += 0.01;
|
minorPlanetMesh.rotation.y = (simDate.getTime() / 1000) * 0.0002;
|
||||||
minorPlanetOrbitLine.visible = showOrbits;
|
minorPlanetOrbitLine.visible = showOrbits;
|
||||||
|
|
||||||
if (focusedMinorPlanetId === selectedMinorPlanetId) {
|
if (focusedMinorPlanetId === selectedMinorPlanetId) {
|
||||||
@@ -839,6 +1001,8 @@ function rebuildOrbitLine(planet) {
|
|||||||
|
|
||||||
function createPlanetMesh(planet) {
|
function createPlanetMesh(planet) {
|
||||||
const group = new THREE.Group();
|
const group = new THREE.Group();
|
||||||
|
const axisGroup = new THREE.Group();
|
||||||
|
const spinGroup = new THREE.Group();
|
||||||
const matParams = {
|
const matParams = {
|
||||||
emissive: new THREE.Color(planet.emissive),
|
emissive: new THREE.Color(planet.emissive),
|
||||||
emissiveIntensity: 0.12,
|
emissiveIntensity: 0.12,
|
||||||
@@ -862,7 +1026,8 @@ function createPlanetMesh(planet) {
|
|||||||
);
|
);
|
||||||
mesh.castShadow = true;
|
mesh.castShadow = true;
|
||||||
mesh.receiveShadow = true;
|
mesh.receiveShadow = true;
|
||||||
group.add(mesh);
|
spinGroup.add(mesh);
|
||||||
|
axisGroup.add(spinGroup);
|
||||||
|
|
||||||
|
|
||||||
if (planet.key === 'Saturn') {
|
if (planet.key === 'Saturn') {
|
||||||
@@ -898,13 +1063,18 @@ function createPlanetMesh(planet) {
|
|||||||
);
|
);
|
||||||
ring.castShadow = true;
|
ring.castShadow = true;
|
||||||
ring.receiveShadow = true;
|
ring.receiveShadow = true;
|
||||||
ring.rotation.x = Math.PI * 0.43;
|
ring.rotation.x = Math.PI / 2;
|
||||||
group.add(ring);
|
axisGroup.add(ring);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
group.add(axisGroup);
|
||||||
|
|
||||||
group.userData.planetKey = planet.key;
|
group.userData.planetKey = planet.key;
|
||||||
group.userData.baseScale = 1;
|
group.userData.baseScale = 1;
|
||||||
group.userData.minScaleMultiplier = Math.max(JUPITER_MIN_VISIBLE_SIZE / Math.max(planet.size, 0.001), 1);
|
group.userData.minScaleMultiplier = Math.max(JUPITER_MIN_VISIBLE_SIZE / Math.max(planet.size, 0.001), 1);
|
||||||
|
group.userData.axisGroup = axisGroup;
|
||||||
|
group.userData.spinGroup = spinGroup;
|
||||||
|
group.userData.surfaceMesh = mesh;
|
||||||
scene.add(group);
|
scene.add(group);
|
||||||
planetMeshes.set(planet.key, group);
|
planetMeshes.set(planet.key, group);
|
||||||
createOrbitLine(planet);
|
createOrbitLine(planet);
|
||||||
@@ -935,6 +1105,7 @@ function createEclipticPlane() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updatePlanetPositions() {
|
function updatePlanetPositions() {
|
||||||
|
const upAxis = new THREE.Vector3(0, 1, 0);
|
||||||
PLANETS.forEach((planet) => {
|
PLANETS.forEach((planet) => {
|
||||||
const meshGroup = planetMeshes.get(planet.key);
|
const meshGroup = planetMeshes.get(planet.key);
|
||||||
if (!meshGroup) {
|
if (!meshGroup) {
|
||||||
@@ -944,7 +1115,14 @@ function updatePlanetPositions() {
|
|||||||
const heliocentric = getHelioPosition(planet.key, simDate);
|
const heliocentric = getHelioPosition(planet.key, simDate);
|
||||||
const display = toDisplayPosition(heliocentric);
|
const display = toDisplayPosition(heliocentric);
|
||||||
meshGroup.position.copy(display);
|
meshGroup.position.copy(display);
|
||||||
meshGroup.children[0].rotation.y += 0.004;
|
|
||||||
|
const axisGroup = meshGroup.userData.axisGroup;
|
||||||
|
const spinGroup = meshGroup.userData.spinGroup;
|
||||||
|
const rotationState = getPlanetRotationState(planet.key, simDate);
|
||||||
|
if (axisGroup && spinGroup && rotationState) {
|
||||||
|
axisGroup.quaternion.setFromUnitVectors(upAxis, rotationState.northDisplay);
|
||||||
|
spinGroup.rotation.y = rotationState.spinRad;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -968,6 +1146,10 @@ function updateBodyDisplayScales() {
|
|||||||
applyMinimumDisplayScale(group, 180, 6);
|
applyMinimumDisplayScale(group, 180, 6);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (moonMesh) {
|
||||||
|
applyMinimumDisplayScale(moonMesh, 220, 10);
|
||||||
|
}
|
||||||
|
|
||||||
if (minorPlanetMesh && minorPlanetMesh.visible) {
|
if (minorPlanetMesh && minorPlanetMesh.visible) {
|
||||||
applyMinimumDisplayScale(minorPlanetMesh, 220, 10);
|
applyMinimumDisplayScale(minorPlanetMesh, 220, 10);
|
||||||
}
|
}
|
||||||
@@ -997,6 +1179,20 @@ function updateLabels() {
|
|||||||
label.style.top = `${(-projected.y * 0.5 + 0.5) * stageWrap.clientHeight}px`;
|
label.style.top = `${(-projected.y * 0.5 + 0.5) * stageWrap.clientHeight}px`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (moonLabelElement && moonMesh) {
|
||||||
|
moonLabelElement.hidden = !showLabels;
|
||||||
|
if (!moonLabelElement.hidden) {
|
||||||
|
const projectedMoon = moonMesh.position.clone().project(camera);
|
||||||
|
if (projectedMoon.z > 1) {
|
||||||
|
moonLabelElement.style.opacity = '0';
|
||||||
|
} else {
|
||||||
|
moonLabelElement.style.opacity = '1';
|
||||||
|
moonLabelElement.style.left = `${(projectedMoon.x * 0.5 + 0.5) * stageWrap.clientWidth}px`;
|
||||||
|
moonLabelElement.style.top = `${(-projectedMoon.y * 0.5 + 0.5) * stageWrap.clientHeight}px`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!minorPlanetLabelElement || !minorPlanetMesh) {
|
if (!minorPlanetLabelElement || !minorPlanetMesh) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1027,7 +1223,10 @@ function pickPlanet(clientX, clientY) {
|
|||||||
|
|
||||||
const meshes = [];
|
const meshes = [];
|
||||||
planetMeshes.forEach((group, key) => {
|
planetMeshes.forEach((group, key) => {
|
||||||
meshes.push({ key, mesh: group.children[0] });
|
const surfaceMesh = group.userData.surfaceMesh;
|
||||||
|
if (surfaceMesh) {
|
||||||
|
meshes.push({ key, mesh: surfaceMesh });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const hits = raycaster.intersectObjects(meshes.map((item) => item.mesh), false);
|
const hits = raycaster.intersectObjects(meshes.map((item) => item.mesh), false);
|
||||||
@@ -1140,6 +1339,9 @@ function attachUiHandlers() {
|
|||||||
if (minorPlanetOrbitLine) {
|
if (minorPlanetOrbitLine) {
|
||||||
minorPlanetOrbitLine.visible = showOrbits && !!getMinorPlanetMeta(selectedMinorPlanetId);
|
minorPlanetOrbitLine.visible = showOrbits && !!getMinorPlanetMeta(selectedMinorPlanetId);
|
||||||
}
|
}
|
||||||
|
if (moonOrbitLine) {
|
||||||
|
moonOrbitLine.visible = showOrbits;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
btnLabels.addEventListener('click', () => {
|
btnLabels.addEventListener('click', () => {
|
||||||
@@ -1194,6 +1396,7 @@ function animate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updatePlanetPositions();
|
updatePlanetPositions();
|
||||||
|
updateMoonVisual();
|
||||||
updateMinorPlanetVisual();
|
updateMinorPlanetVisual();
|
||||||
|
|
||||||
// Aim shadow light from sun toward Saturn
|
// Aim shadow light from sun toward Saturn
|
||||||
@@ -1231,6 +1434,9 @@ function animate() {
|
|||||||
const planet = PLANETS[(orbitRefreshCursor / 90) % PLANETS.length | 0];
|
const planet = PLANETS[(orbitRefreshCursor / 90) % PLANETS.length | 0];
|
||||||
rebuildOrbitLine(planet);
|
rebuildOrbitLine(planet);
|
||||||
}
|
}
|
||||||
|
if (playing && orbitRefreshCursor % 45 === 0) {
|
||||||
|
rebuildMoonOrbitLine();
|
||||||
|
}
|
||||||
renderer.render(scene, camera);
|
renderer.render(scene, camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1344,6 +1550,7 @@ async function initSolarSystem() {
|
|||||||
|
|
||||||
buildLabels();
|
buildLabels();
|
||||||
PLANETS.forEach(createPlanetMesh);
|
PLANETS.forEach(createPlanetMesh);
|
||||||
|
ensureMoonObjects();
|
||||||
ensureMinorPlanetObjects();
|
ensureMinorPlanetObjects();
|
||||||
attachPointerControls();
|
attachPointerControls();
|
||||||
attachUiHandlers();
|
attachUiHandlers();
|
||||||
@@ -1351,6 +1558,8 @@ async function initSolarSystem() {
|
|||||||
refreshCurrentDateUi();
|
refreshCurrentDateUi();
|
||||||
resizeRenderer();
|
resizeRenderer();
|
||||||
updatePlanetPositions();
|
updatePlanetPositions();
|
||||||
|
rebuildMoonOrbitLine();
|
||||||
|
updateMoonVisual();
|
||||||
rebuildMinorPlanetOrbit(null);
|
rebuildMinorPlanetOrbit(null);
|
||||||
updateCamera();
|
updateCamera();
|
||||||
overlay.hidden = true;
|
overlay.hidden = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user