diff --git a/public/index.html b/public/index.html index ac66b1084530036ea47498df249c4bf6c57d0f08..43379c02ad640d9520e808892dcc874055dc4af3 100644 --- a/public/index.html +++ b/public/index.html @@ -1,62 +1,98 @@ -<!DOCTYPE html> +<!doctype html> <html lang="de"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>AR mit HTML-Menü</title> - <script src="https://unpkg.com/three@0.126.0/build/three.js"></script> - <script src="https://unpkg.com/three@0.126.0/examples/js/loaders/GLTFLoader.js"></script> + <title>GeoVis AR Projekt</title> <style> body { margin: 0; - overflow: hidden; + font-family: Arial, sans-serif; + background-color: #f0f0f0; + color: #333; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + background-image: url('https://www.hft-stuttgart.de/fileadmin/Dateien/Hochschule/-_R_Juergen_Pollak_HFT_18.04.18-0091.jpg'); + background-size: cover; + background-position: center; } - /* HTML-Menü für Modelle */ - #menu { - position: fixed; - bottom: 10px; - left: 50%; - transform: translateX(-50%); - display: flex; - gap: 10px; - background: rgba(0, 0, 0, 0.7); - padding: 10px; + .container { + text-align: center; + background-color: rgba(0, 0, 0, 0.5); + padding: 50px; border-radius: 10px; + color: white; + max-width: 80%; + box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.5); + } + + h1 { + font-size: 3em; + margin-bottom: 20px; + } + + p { + font-size: 1.2em; + margin-bottom: 30px; } button { - padding: 10px; - background: #2196F3; + background-color: #4CAF50; color: white; + font-size: 1.5em; + padding: 15px 30px; border: none; border-radius: 5px; cursor: pointer; - font-size: 14px; + transition: background-color 0.3s; + margin: 10px; } button:hover { - background: #1976D2; + background-color: #45a049; + } + + button:active { + background-color: #387a39; + } + + .menu-bar { + position: fixed; + top: 0; + left: 0; + right: 0; + display: flex; + justify-content: center; + background-color: rgba(0, 0, 0, 0.7); + padding: 10px; + z-index: 10; + } + + .menu-bar button { + background-color: #2196F3; + margin: 0 10px; + } + + .menu-bar button:hover { + background-color: #1E88E5; } </style> + <script src="https://unpkg.com/three@0.126.0/build/three.js"></script> + <script src="https://unpkg.com/three@0.126.0/examples/js/loaders/GLTFLoader.js"></script> </head> <body> - <!-- Menü für Auswahl der Modelle --> - <div id="menu"> - <button onclick="selectModel('robot')">Roboter</button> - <button onclick="selectModel('tree')">Baum</button> - <button onclick="selectModel('lamp')">Lampe</button> - </div> - <script> - let selectedModel = 'robot'; + let selectedModel = 'robot'; // Standardauswahl let models = {}; let reticle; + let menu; async function activateXR() { const canvas = document.createElement('canvas'); document.body.appendChild(canvas); - const gl = canvas.getContext('webgl', { xrCompatible: true }); const renderer = new THREE.WebGLRenderer({ alpha: true, canvas, context: gl }); renderer.autoClear = false; @@ -70,7 +106,7 @@ light.position.set(10, 10, 10); scene.add(light); - // Reticle (Cursor zum Platzieren) + // Reticle (Cursor) const loader = new THREE.GLTFLoader(); loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/reticle/reticle.gltf", (gltf) => { reticle = gltf.scene; @@ -79,9 +115,36 @@ }); // Modelle laden - loader.load("https://threejs.org/examples/models/gltf/RobotExpressive/RobotExpressive.glb", (gltf) => models.robot = gltf.scene); - loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/sunflower/sunflower.gltf", (gltf) => models.tree = gltf.scene); - loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/lamp/lamp.gltf", (gltf) => models.lamp = gltf.scene); + loader.load("https://threejs.org/examples/models/gltf/RobotExpressive/RobotExpressive.glb", (gltf) => { + models.robot = gltf.scene; + }); + loader.load("https://immersive-web.github.io/webxr-samples/media/gltf/sunflower/sunflower.gltf", (gltf) => { + models.sunflower = gltf.scene; + }); + + // AR-Menü erstellen + const menuGeometry = new THREE.PlaneGeometry(0.5, 0.2); // Menügröße + const menuMaterial = new THREE.MeshBasicMaterial({ color: 0x333333, opacity: 0.8, transparent: true }); + menu = new THREE.Mesh(menuGeometry, menuMaterial); + menu.position.set(0, -0.5, -1); // Unten im Kamerasichtfeld + scene.add(menu); + + // Menü-Buttons als Flächen + const buttonGeometry = new THREE.PlaneGeometry(0.15, 0.1); + const buttonMaterial1 = new THREE.MeshBasicMaterial({ color: 0x2196F3 }); + const buttonMaterial2 = new THREE.MeshBasicMaterial({ color: 0xFF9800 }); + + const robotButton = new THREE.Mesh(buttonGeometry, buttonMaterial1); + robotButton.position.set(-0.2, -0.5, -0.99); // Links unten + scene.add(robotButton); + + const sunflowerButton = new THREE.Mesh(buttonGeometry, buttonMaterial2); + sunflowerButton.position.set(0.2, -0.5, -0.99); // Rechts unten + scene.add(sunflowerButton); + + // Raycaster für Button-Interaktion + const raycaster = new THREE.Raycaster(); + const pointer = new THREE.Vector2(); // AR-Session starten const session = await navigator.xr.requestSession('immersive-ar', { requiredFeatures: ['hit-test'] }); @@ -92,9 +155,27 @@ session.requestAnimationFrame(onXRFrame); - // Modell platzieren - session.addEventListener("select", () => { - if (reticle && models[selectedModel]) { + session.addEventListener("select", (event) => { + if (!reticle) return; + + // Raycaster von der Kameraposition (Mitte des Bildschirms) + raycaster.setFromCamera(pointer, camera); + const intersects = raycaster.intersectObjects([robotButton, sunflowerButton]); + + // Prüfen, ob ein Button getroffen wurde + if (intersects.length > 0) { + const clickedButton = intersects[0].object; + + if (clickedButton === robotButton) { + selectedModel = 'robot'; + console.log('Robot ausgewählt'); + } else if (clickedButton === sunflowerButton) { + selectedModel = 'sunflower'; + console.log('Sunflower ausgewählt'); + } + } + // Kein Button getroffen -> Modell platzieren + else if (models[selectedModel]) { const clone = models[selectedModel].clone(); clone.position.copy(reticle.position); clone.scale.set(0.5, 0.5, 0.5); // Größe anpassen @@ -118,6 +199,13 @@ camera.projectionMatrix.fromArray(view.projectionMatrix); camera.updateMatrixWorld(true); + // Menü bleibt fixiert vor der Kamera + menu.position.set(0, -0.5, -1); + menu.lookAt(camera.position); + + robotButton.position.set(-0.2, -0.5, -0.99); + sunflowerButton.position.set(0.2, -0.5, -0.99); + const hitTestResults = frame.getHitTestResults(hitTestSource); if (hitTestResults.length > 0) { const hitPose = hitTestResults[0].getPose(referenceSpace); @@ -131,12 +219,6 @@ } } - // Funktion, um das Modell zu wechseln - function selectModel(modelName) { - selectedModel = modelName; - console.log(`Ausgewähltes Modell: ${selectedModel}`); - } - // AR starten if (navigator.xr) { const startButton = document.createElement('button');