Mars eingebaut und Texturen verbessert
@@ -61,6 +61,7 @@ function manageablePublicPages(): array
|
||||
'astronomical_conversions.php' => 'Astronomical Conversions',
|
||||
'tcrb_lightcurve.php' => 'T CrB Lichtkurve',
|
||||
'solarsystem.php' => 'Sonnensystem',
|
||||
'mars.php' => 'Mars',
|
||||
'jupitersystem.php' => 'Jupitersystem',
|
||||
'tagbogen.php' => 'Tagbogen',
|
||||
'sternenhimmel.php' => 'Sternenhimmel',
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/auth_helpers.php';
|
||||
if (!isset($loggedIn)) {
|
||||
$loggedIn = isset($_SESSION['user_id']);
|
||||
}
|
||||
|
||||
$title = isset($pageTitle) && is_string($pageTitle) && $pageTitle !== ''
|
||||
? $pageTitle
|
||||
: 'Skyview & AstroTools - Astronomiemuseum der Sternwarte Sonneberg';
|
||||
@@ -123,6 +127,7 @@ $menuGroups = [
|
||||
['href' => 'astronomical_conversions.php', 'label' => 'Astronomical Conversions'],
|
||||
['href' => 'tcrb_lightcurve.php', 'label' => 'T CrB Lichtkurve'],
|
||||
['href' => 'solarsystem.php', 'label' => 'Sonnensystem'],
|
||||
['href' => 'mars.php', 'label' => 'Mars'],
|
||||
['href' => 'jupitersystem.php', 'label' => 'Jupitersystem'],
|
||||
['href' => 'tagbogen.php', 'label' => 'Tagbogen'],
|
||||
['href' => 'sternenhimmel.php', 'label' => 'Sternenhimmel'],
|
||||
@@ -178,9 +183,9 @@ if ($loggedIn && !$hasFullAdminAccess && $pdoHeader !== null) {
|
||||
foreach ($menuGroups as &$group) {
|
||||
$group['links'] = array_values(array_filter(
|
||||
$group['links'],
|
||||
static function (array $link) use ($allowedPageKeys): bool {
|
||||
static function (array $link) use ($allowedPageKeys, $publicAccessAllowlist): bool {
|
||||
$href = trim((string) ($link['href'] ?? ''));
|
||||
return $href !== '' && isset($allowedPageKeys[$href]);
|
||||
return $href !== '' && (isset($allowedPageKeys[$href]) || in_array($href, $publicAccessAllowlist, true));
|
||||
}
|
||||
));
|
||||
}
|
||||
@@ -193,9 +198,9 @@ if ($loggedIn && !$hasFullAdminAccess && $pdoHeader !== null) {
|
||||
|
||||
$accountLinks = array_values(array_filter(
|
||||
$accountLinks,
|
||||
static function (array $link) use ($allowedPageKeys): bool {
|
||||
static function (array $link) use ($allowedPageKeys, $publicAccessAllowlist): bool {
|
||||
$href = trim((string) ($link['href'] ?? ''));
|
||||
return $href !== '' && isset($allowedPageKeys[$href]);
|
||||
return $href !== '' && (isset($allowedPageKeys[$href]) || in_array($href, $publicAccessAllowlist, true));
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 686 KiB After Width: | Height: | Size: 648 KiB |
|
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 8.0 MiB After Width: | Height: | Size: 7.1 MiB |
|
After Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 236 KiB |
@@ -0,0 +1,240 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
ini_set('display_errors', '1');
|
||||
error_reporting(E_ALL);
|
||||
session_start();
|
||||
|
||||
$pageTitle = 'Mars - AstroTools';
|
||||
$bodyClass = 'mars-page';
|
||||
$headerIntroPre = 'Planetendarstellung';
|
||||
$headerIntroTitle = 'Mars';
|
||||
$headerIntroSub = 'Eine einfache 3D-Ansicht mit Marstextur.';
|
||||
?>
|
||||
<?php require __DIR__ . '/header.php'; ?>
|
||||
|
||||
<style>
|
||||
.mars-stage-card {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.mars-stage {
|
||||
position: relative;
|
||||
min-height: 70vh;
|
||||
background:
|
||||
radial-gradient(circle at top, rgba(255, 153, 102, 0.12), transparent 40%),
|
||||
linear-gradient(180deg, rgba(14, 10, 10, 0.94), rgba(8, 8, 12, 0.98));
|
||||
}
|
||||
|
||||
#marsViewport {
|
||||
width: 100%;
|
||||
height: 70vh;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.mars-overlay {
|
||||
position: absolute;
|
||||
left: 1rem;
|
||||
bottom: 1rem;
|
||||
padding: 0.6rem 0.85rem;
|
||||
border-radius: 999px;
|
||||
background: rgba(15, 15, 22, 0.72);
|
||||
color: #f4e7de;
|
||||
font-size: 0.95rem;
|
||||
letter-spacing: 0.02em;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.mars-stage,
|
||||
#marsViewport {
|
||||
height: 58vh;
|
||||
min-height: 420px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<section class="card mars-stage-card">
|
||||
<div class="mars-stage">
|
||||
<canvas id="marsViewport" aria-label="3D-Ansicht des Mars"></canvas>
|
||||
<div class="mars-overlay">Ziehen zum Drehen, Mausrad zum Zoomen</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script type="module">
|
||||
let THREE;
|
||||
|
||||
async function initMars() {
|
||||
THREE = await import('./js/three.module.js');
|
||||
|
||||
const canvas = document.getElementById('marsViewport');
|
||||
if (!canvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({
|
||||
canvas,
|
||||
antialias: true,
|
||||
alpha: true
|
||||
});
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
|
||||
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
||||
renderer.shadowMap.enabled = true;
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
||||
renderer.toneMappingExposure = 1.05;
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
|
||||
const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 100);
|
||||
camera.position.set(0, 0, 4.8);
|
||||
|
||||
const hemisphereLight = new THREE.HemisphereLight(0x9db4d8, 0x120d0b, 0.16);
|
||||
scene.add(hemisphereLight);
|
||||
|
||||
const sunLight = new THREE.DirectionalLight(0xfff1d6, 2.8);
|
||||
sunLight.position.set(7, 1.8, 5.5);
|
||||
sunLight.castShadow = true;
|
||||
sunLight.shadow.mapSize.set(2048, 2048);
|
||||
sunLight.shadow.bias = -0.0008;
|
||||
sunLight.shadow.normalBias = 0.02;
|
||||
sunLight.shadow.camera.near = 1;
|
||||
sunLight.shadow.camera.far = 20;
|
||||
sunLight.shadow.camera.left = -4;
|
||||
sunLight.shadow.camera.right = 4;
|
||||
sunLight.shadow.camera.top = 4;
|
||||
sunLight.shadow.camera.bottom = -4;
|
||||
sunLight.target.position.set(0, 0, 0);
|
||||
scene.add(sunLight);
|
||||
scene.add(sunLight.target);
|
||||
|
||||
const fillLight = new THREE.DirectionalLight(0xa4b4d8, 0.18);
|
||||
fillLight.position.set(-4, -1.5, -3.5);
|
||||
scene.add(fillLight);
|
||||
|
||||
const loader = new THREE.TextureLoader();
|
||||
const marsTexture = loader.load('./images/planets/mars_4096.jpg');
|
||||
marsTexture.colorSpace = THREE.SRGBColorSpace;
|
||||
marsTexture.anisotropy = renderer.capabilities.getMaxAnisotropy();
|
||||
const marsDisplacement = loader.load('./images/planets/mars_displacement_5760.jpg');
|
||||
marsDisplacement.anisotropy = renderer.capabilities.getMaxAnisotropy();
|
||||
|
||||
const geometry = new THREE.SphereGeometry(1.45, 192, 192);
|
||||
const material = new THREE.MeshStandardMaterial({
|
||||
map: marsTexture,
|
||||
displacementMap: marsDisplacement,
|
||||
displacementScale: 0.065,
|
||||
displacementBias: -0.02,
|
||||
bumpMap: marsDisplacement,
|
||||
bumpScale: 0.03,
|
||||
roughness: 0.96,
|
||||
metalness: 0
|
||||
});
|
||||
|
||||
const mars = new THREE.Mesh(geometry, material);
|
||||
mars.castShadow = true;
|
||||
mars.receiveShadow = true;
|
||||
scene.add(mars);
|
||||
|
||||
const state = {
|
||||
isPointerDown: false,
|
||||
lastX: 0,
|
||||
lastY: 0,
|
||||
velocityX: 0,
|
||||
velocityY: 0
|
||||
};
|
||||
|
||||
canvas.style.touchAction = 'none';
|
||||
|
||||
function resizeRenderer() {
|
||||
const width = canvas.clientWidth;
|
||||
const height = canvas.clientHeight;
|
||||
if (width === 0 || height === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderer.setSize(width, height, false);
|
||||
camera.aspect = width / height;
|
||||
camera.updateProjectionMatrix();
|
||||
}
|
||||
|
||||
function clampCameraDistance(nextZ) {
|
||||
return Math.min(Math.max(nextZ, 3.2), 8.5);
|
||||
}
|
||||
|
||||
function onPointerDown(event) {
|
||||
state.isPointerDown = true;
|
||||
state.lastX = event.clientX;
|
||||
state.lastY = event.clientY;
|
||||
canvas.setPointerCapture(event.pointerId);
|
||||
}
|
||||
|
||||
function onPointerMove(event) {
|
||||
if (!state.isPointerDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
const deltaX = event.clientX - state.lastX;
|
||||
const deltaY = event.clientY - state.lastY;
|
||||
state.lastX = event.clientX;
|
||||
state.lastY = event.clientY;
|
||||
|
||||
const rotationSpeed = 0.008;
|
||||
mars.rotation.y += deltaX * rotationSpeed;
|
||||
mars.rotation.x += deltaY * rotationSpeed;
|
||||
mars.rotation.x = Math.max(-1.25, Math.min(1.25, mars.rotation.x));
|
||||
|
||||
state.velocityX = deltaX * 0.0009;
|
||||
state.velocityY = deltaY * 0.0009;
|
||||
}
|
||||
|
||||
function onPointerUp(event) {
|
||||
state.isPointerDown = false;
|
||||
if (canvas.hasPointerCapture(event.pointerId)) {
|
||||
canvas.releasePointerCapture(event.pointerId);
|
||||
}
|
||||
}
|
||||
|
||||
function onWheel(event) {
|
||||
event.preventDefault();
|
||||
camera.position.z = clampCameraDistance(camera.position.z + event.deltaY * 0.0035);
|
||||
}
|
||||
|
||||
function renderFrame() {
|
||||
if (!state.isPointerDown) {
|
||||
mars.rotation.y += state.velocityX;
|
||||
mars.rotation.x += state.velocityY;
|
||||
mars.rotation.x = Math.max(-1.25, Math.min(1.25, mars.rotation.x));
|
||||
state.velocityX *= 0.94;
|
||||
state.velocityY *= 0.94;
|
||||
|
||||
if (Math.abs(state.velocityX) < 0.00001) {
|
||||
state.velocityX = 0;
|
||||
}
|
||||
if (Math.abs(state.velocityY) < 0.00001) {
|
||||
state.velocityY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
renderer.render(scene, camera);
|
||||
requestAnimationFrame(renderFrame);
|
||||
}
|
||||
|
||||
canvas.addEventListener('pointerdown', onPointerDown);
|
||||
canvas.addEventListener('pointermove', onPointerMove);
|
||||
canvas.addEventListener('pointerup', onPointerUp);
|
||||
canvas.addEventListener('pointercancel', onPointerUp);
|
||||
canvas.addEventListener('wheel', onWheel, { passive: false });
|
||||
|
||||
window.addEventListener('resize', resizeRenderer);
|
||||
resizeRenderer();
|
||||
renderFrame();
|
||||
}
|
||||
|
||||
initMars().catch((error) => {
|
||||
console.error('Mars-Ansicht konnte nicht initialisiert werden.', error);
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php require __DIR__ . '/footer.php'; ?>
|
||||