Sonnensystem verbessert
This commit is contained in:
+215
-6
@@ -271,6 +271,7 @@ const AU_IN_KM = 149597870.7;
|
||||
const DISPLAY_SCALE = 34;
|
||||
const USER_MINOR_PLANETS = <?= json_encode($trackedMinorplanetsForJs, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||||
const JUPITER_MIN_VISIBLE_SIZE = 1.42;
|
||||
const MOON_DISPLAY_DISTANCE_MULTIPLIER = 2200;
|
||||
|
||||
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' },
|
||||
@@ -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: '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 canvas = document.getElementById('solarCanvas');
|
||||
@@ -320,6 +333,9 @@ let raycaster;
|
||||
let pointer;
|
||||
let eclipticGroup;
|
||||
let rotationEqjToEcl;
|
||||
let moonMesh = null;
|
||||
let moonOrbitLine = null;
|
||||
let moonLabelElement = null;
|
||||
let minorPlanetOrbitLine = null;
|
||||
let minorPlanetMesh = 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() {
|
||||
currentDateLabel.textContent = formatDisplayDate(simDate);
|
||||
datePicker.value = formatDateInput(simDate);
|
||||
@@ -608,6 +693,83 @@ function buildLabels() {
|
||||
labelsLayer.appendChild(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() {
|
||||
@@ -783,7 +945,7 @@ function updateMinorPlanetVisual() {
|
||||
const display = toDisplayPosition(heliocentric);
|
||||
minorPlanetMesh.visible = true;
|
||||
minorPlanetMesh.position.copy(display);
|
||||
minorPlanetMesh.rotation.y += 0.01;
|
||||
minorPlanetMesh.rotation.y = (simDate.getTime() / 1000) * 0.0002;
|
||||
minorPlanetOrbitLine.visible = showOrbits;
|
||||
|
||||
if (focusedMinorPlanetId === selectedMinorPlanetId) {
|
||||
@@ -839,6 +1001,8 @@ function rebuildOrbitLine(planet) {
|
||||
|
||||
function createPlanetMesh(planet) {
|
||||
const group = new THREE.Group();
|
||||
const axisGroup = new THREE.Group();
|
||||
const spinGroup = new THREE.Group();
|
||||
const matParams = {
|
||||
emissive: new THREE.Color(planet.emissive),
|
||||
emissiveIntensity: 0.12,
|
||||
@@ -862,7 +1026,8 @@ function createPlanetMesh(planet) {
|
||||
);
|
||||
mesh.castShadow = true;
|
||||
mesh.receiveShadow = true;
|
||||
group.add(mesh);
|
||||
spinGroup.add(mesh);
|
||||
axisGroup.add(spinGroup);
|
||||
|
||||
|
||||
if (planet.key === 'Saturn') {
|
||||
@@ -898,13 +1063,18 @@ function createPlanetMesh(planet) {
|
||||
);
|
||||
ring.castShadow = true;
|
||||
ring.receiveShadow = true;
|
||||
ring.rotation.x = Math.PI * 0.43;
|
||||
group.add(ring);
|
||||
ring.rotation.x = Math.PI / 2;
|
||||
axisGroup.add(ring);
|
||||
}
|
||||
|
||||
group.add(axisGroup);
|
||||
|
||||
group.userData.planetKey = planet.key;
|
||||
group.userData.baseScale = 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);
|
||||
planetMeshes.set(planet.key, group);
|
||||
createOrbitLine(planet);
|
||||
@@ -935,6 +1105,7 @@ function createEclipticPlane() {
|
||||
}
|
||||
|
||||
function updatePlanetPositions() {
|
||||
const upAxis = new THREE.Vector3(0, 1, 0);
|
||||
PLANETS.forEach((planet) => {
|
||||
const meshGroup = planetMeshes.get(planet.key);
|
||||
if (!meshGroup) {
|
||||
@@ -944,7 +1115,14 @@ function updatePlanetPositions() {
|
||||
const heliocentric = getHelioPosition(planet.key, simDate);
|
||||
const display = toDisplayPosition(heliocentric);
|
||||
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);
|
||||
});
|
||||
|
||||
if (moonMesh) {
|
||||
applyMinimumDisplayScale(moonMesh, 220, 10);
|
||||
}
|
||||
|
||||
if (minorPlanetMesh && minorPlanetMesh.visible) {
|
||||
applyMinimumDisplayScale(minorPlanetMesh, 220, 10);
|
||||
}
|
||||
@@ -997,6 +1179,20 @@ function updateLabels() {
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
@@ -1027,7 +1223,10 @@ function pickPlanet(clientX, clientY) {
|
||||
|
||||
const meshes = [];
|
||||
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);
|
||||
@@ -1140,6 +1339,9 @@ function attachUiHandlers() {
|
||||
if (minorPlanetOrbitLine) {
|
||||
minorPlanetOrbitLine.visible = showOrbits && !!getMinorPlanetMeta(selectedMinorPlanetId);
|
||||
}
|
||||
if (moonOrbitLine) {
|
||||
moonOrbitLine.visible = showOrbits;
|
||||
}
|
||||
});
|
||||
|
||||
btnLabels.addEventListener('click', () => {
|
||||
@@ -1194,6 +1396,7 @@ function animate() {
|
||||
}
|
||||
|
||||
updatePlanetPositions();
|
||||
updateMoonVisual();
|
||||
updateMinorPlanetVisual();
|
||||
|
||||
// Aim shadow light from sun toward Saturn
|
||||
@@ -1231,6 +1434,9 @@ function animate() {
|
||||
const planet = PLANETS[(orbitRefreshCursor / 90) % PLANETS.length | 0];
|
||||
rebuildOrbitLine(planet);
|
||||
}
|
||||
if (playing && orbitRefreshCursor % 45 === 0) {
|
||||
rebuildMoonOrbitLine();
|
||||
}
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
@@ -1344,6 +1550,7 @@ async function initSolarSystem() {
|
||||
|
||||
buildLabels();
|
||||
PLANETS.forEach(createPlanetMesh);
|
||||
ensureMoonObjects();
|
||||
ensureMinorPlanetObjects();
|
||||
attachPointerControls();
|
||||
attachUiHandlers();
|
||||
@@ -1351,6 +1558,8 @@ async function initSolarSystem() {
|
||||
refreshCurrentDateUi();
|
||||
resizeRenderer();
|
||||
updatePlanetPositions();
|
||||
rebuildMoonOrbitLine();
|
||||
updateMoonVisual();
|
||||
rebuildMinorPlanetOrbit(null);
|
||||
updateCamera();
|
||||
overlay.hidden = true;
|
||||
|
||||
Reference in New Issue
Block a user