diff --git a/public/index.html b/public/index.html index effde1c981e7a97b6d3950b6c8ba7a6e7f721388..b4b39c0f51252217453a5751704d57773426d23e 100644 --- a/public/index.html +++ b/public/index.html @@ -1,91 +1,95 @@ -<!doctype html> +<!DOCTYPE html> <html lang="de"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>GeoVis AR Projekt</title> + <title>AR Kamera mit Menüleiste</title> <style> - body { + * { margin: 0; + padding: 0; + box-sizing: border-box; + } + + body { font-family: Arial, sans-serif; - background-color: #f0f0f0; - color: #333; + background-color: #000; + color: #fff; display: flex; - justify-content: center; - align-items: center; + flex-direction: column; 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; - } - .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); + overflow: hidden; } - h1 { - font-size: 3em; - margin-bottom: 20px; + + /* Container für die AR-Kamera */ + #camera-container { + flex: 1; /* Nimmt den oberen Teil des Bildschirms ein */ + position: relative; + background-color: #111; } - p { - font-size: 1.2em; - margin-bottom: 30px; + + /* Menüleiste unterhalb der Kamera */ + #menu-bar { + height: 80px; /* Höhe der Menüleiste */ + background-color: rgba(0, 0, 0, 0.8); + display: flex; + justify-content: space-around; + align-items: center; + border-top: 2px solid #333; } + button { - background-color: #4CAF50; - color: white; - font-size: 1.5em; - padding: 15px 30px; + background-color: #2196F3; + color: #fff; + font-size: 16px; + padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; transition: background-color 0.3s; - margin: 10px; } + button:hover { - background-color: #45a049; - } - button:active { - background-color: #387a39; + 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> + <!-- AR-Kamera-Container --> + <div id="camera-container"></div> + + <!-- Menüleiste --> + <div id="menu-bar"> + <button onclick="selectModel('car')">Auto</button> + <button onclick="selectModel('lamp')">Lampe</button> + </div> + + <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> <script> - let selectedModel = 'car'; // Standardmodell + let selectedModel = 'car'; let models = {}; - let reticle; 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; + const cameraContainer = document.getElementById('camera-container'); + // Renderer erstellen + const renderer = new THREE.WebGLRenderer({ alpha: true }); + renderer.setSize(cameraContainer.clientWidth, cameraContainer.clientHeight); + cameraContainer.appendChild(renderer.domElement); + + // Szene und Kamera erstellen const scene = new THREE.Scene(); - const camera = new THREE.PerspectiveCamera(); - camera.matrixAutoUpdate = false; + const camera = new THREE.PerspectiveCamera(70, cameraContainer.clientWidth / cameraContainer.clientHeight, 0.01, 100); + camera.position.z = 2; + // Licht hinzufügen const light = new THREE.DirectionalLight(0xffffff, 1); light.position.set(10, 10, 10); scene.add(light); - // 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; - reticle.visible = false; - scene.add(reticle); - }); - // Modelle laden + const loader = new THREE.GLTFLoader(); loader.load("https://threejs.org/examples/models/gltf/RobotExpressive/RobotExpressive.glb", (gltf) => { models.car = gltf.scene; }); @@ -93,86 +97,40 @@ models.lamp = gltf.scene; }); - // Buttons für Auswahl erstellen - const carButton = document.createElement('button'); - carButton.textContent = 'Auto auswählen'; - document.body.appendChild(carButton); - carButton.style.cssText = "position: fixed; bottom: 20px; left: 20px; z-index: 1000;"; - carButton.onclick = () => { - selectedModel = 'car'; - console.log('Auto ausgewählt'); - }; - - const lampButton = document.createElement('button'); - lampButton.textContent = 'Lampe auswählen'; - document.body.appendChild(lampButton); - lampButton.style.cssText = "position: fixed; bottom: 20px; right: 20px; z-index: 1000;"; - lampButton.onclick = () => { - selectedModel = 'lamp'; - console.log('Lampe ausgewählt'); - }; - - // AR-Session starten - const session = await navigator.xr.requestSession('immersive-ar', { requiredFeatures: ['hit-test'] }); - session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) }); - const referenceSpace = await session.requestReferenceSpace('local'); - const viewerSpace = await session.requestReferenceSpace('viewer'); - const hitTestSource = await session.requestHitTestSource({ space: viewerSpace }); - - session.requestAnimationFrame(onXRFrame); - - session.addEventListener("select", () => { - if (reticle && models[selectedModel]) { - const clone = models[selectedModel].clone(); - clone.position.copy(reticle.position); - clone.scale.set(0.5, 0.5, 0.5); - scene.add(clone); + // Animation + function animate() { + requestAnimationFrame(animate); + renderer.render(scene, camera); + } + animate(); + + // Dummy-Reticle (nur zur Demo) + const reticleGeometry = new THREE.CircleGeometry(0.05, 32); + const reticleMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 }); + const reticle = new THREE.Mesh(reticleGeometry, reticleMaterial); + reticle.position.set(0, -0.5, -2); + scene.add(reticle); + + // Modell platzieren + window.addEventListener('click', () => { + if (models[selectedModel]) { + const modelClone = models[selectedModel].clone(); + modelClone.position.set(0, -0.5, -2); + modelClone.scale.set(0.5, 0.5, 0.5); + scene.add(modelClone); console.log(`${selectedModel} platziert`); } }); - - function onXRFrame(time, frame) { - session.requestAnimationFrame(onXRFrame); - gl.bindFramebuffer(gl.FRAMEBUFFER, session.renderState.baseLayer.framebuffer); - - const pose = frame.getViewerPose(referenceSpace); - if (pose) { - const view = pose.views[0]; - const viewport = session.renderState.baseLayer.getViewport(view); - renderer.setSize(viewport.width, viewport.height); - - camera.matrix.fromArray(view.transform.matrix); - camera.projectionMatrix.fromArray(view.projectionMatrix); - camera.updateMatrixWorld(true); - - const hitTestResults = frame.getHitTestResults(hitTestSource); - if (hitTestResults.length > 0) { - const hitPose = hitTestResults[0].getPose(referenceSpace); - reticle.visible = true; - reticle.position.set(hitPose.transform.position.x, hitPose.transform.position.y, hitPose.transform.position.z); - reticle.updateMatrixWorld(true); - } else { - reticle.visible = false; - } - - renderer.render(scene, camera); - } - } } - // AR starten - if (navigator.xr) { - const startButton = document.createElement('button'); - startButton.textContent = 'Start AR'; - startButton.style.cssText = "position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 15px; font-size: 18px;"; - document.body.appendChild(startButton); - startButton.onclick = () => { - startButton.remove(); - activateXR(); - }; - } else { - alert('WebXR wird nicht unterstützt.'); + // Modell auswählen + function selectModel(model) { + selectedModel = model; + console.log(`${model} ausgewählt`); } + + // AR aktivieren + activateXR(); </script> </body> </html>