Commit 5e700049 authored by Alfakhori's avatar Alfakhori
Browse files

186 v1

parent 8d19a755
Pipeline #12488 passed with stage
in 24 seconds
function downloadScene() { function downloadScene() {
const placedModels = getAllPlacedModels().map(model => { const placedModels = window.getAllPlacedModels().map(model => {
const { lat, lng } = threeToLeaflet(model.position.x, model.position.z); const { lat, lng } = window.threeToLeaflet(model.position.x, model.position.z);
return { return {
name: model.modelConfig.name, name: model.modelConfig.name,
position: model.position, position: model.position,
...@@ -71,3 +71,7 @@ function loadSceneFromFile(loadedData) { ...@@ -71,3 +71,7 @@ function loadSceneFromFile(loadedData) {
}); });
fileInput.click(); fileInput.click();
} }
/* Expose functions used by the existing HTML and ar_start.js. */
window.downloadScene = downloadScene;
window.loadSceneFromFile = loadSceneFromFile;
import * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
/* ========================= */ /* ========================= */
/* GLOBALE VARIABLEN */ /* GLOBALE VARIABLEN */
/* ========================= */ /* ========================= */
...@@ -6,13 +9,14 @@ let selectedPlacedModel = null; ...@@ -6,13 +9,14 @@ let selectedPlacedModel = null;
let currentSession = null; let currentSession = null;
let reticle = null; let reticle = null;
let scene, camera; let scene, camera;
let xrRenderer = null;
let geoLocation; let geoLocation;
const modelCache = new Map(); const modelCache = new Map();
// PERFORMANCE: Reuse one GLTFLoader instead of creating // PERFORMANCE: Reuse one GLTFLoader instead of creating
// a new loader every time a model is placed. // a new loader every time a model is placed.
const gltfLoader = new THREE.GLTFLoader(); const gltfLoader = new GLTFLoader();
const menus = [ const menus = [
'menu-bar', 'menu-bar',
...@@ -514,9 +518,14 @@ function selectModelFromScene(event) { ...@@ -514,9 +518,14 @@ function selectModelFromScene(event) {
new THREE.Raycaster(); new THREE.Raycaster();
const rayCamera =
xrRenderer && xrRenderer.xr.isPresenting
? xrRenderer.xr.getCamera(camera)
: camera;
raycaster.setFromCamera( raycaster.setFromCamera(
mouse, mouse,
camera rayCamera
); );
...@@ -1117,61 +1126,65 @@ async function activateXR(sceneData = null) { ...@@ -1117,61 +1126,65 @@ async function activateXR(sceneData = null) {
document.body.appendChild(canvas); document.body.appendChild(canvas);
const gl = canvas.getContext("webgl", { // ========================================================
xrCompatible: true, // Three.js WebXR renderer
}); // ========================================================
const renderer = new THREE.WebGLRenderer({ const renderer = new THREE.WebGLRenderer({
alpha: true, alpha: true,
antialias: true,
canvas, canvas,
context: gl,
}); });
renderer.autoClear = false; renderer.autoClear = false;
renderer.xr.enabled = true;
xrRenderer = renderer;
scene = new THREE.Scene(); // Keep the same reference-space type used by the previous
// manual WebXR implementation.
renderer.xr.setReferenceSpaceType("local");
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(); camera = new THREE.PerspectiveCamera();
camera.matrixAutoUpdate = false;
// ======================================================== // ========================================================
// AR lighting // AR lighting
// ======================================================== // ========================================================
// Soft overall illumination
const ambientLight = new THREE.AmbientLight(0xffffff, 2.5); const ambientLight = new THREE.AmbientLight(0xffffff, 2.5);
scene.add(ambientLight); scene.add(ambientLight);
// Sky/ground illumination const hemisphereLight =
const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x888888, 1.5); new THREE.HemisphereLight(0xffffff, 0x888888, 1.5);
scene.add(hemisphereLight); scene.add(hemisphereLight);
// Directional light for shadows and form const directionalLight =
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5); new THREE.DirectionalLight(0xffffff, 1.5);
directionalLight.position.set(10, 20, 10); directionalLight.position.set(10, 20, 10);
scene.add(directionalLight); scene.add(directionalLight);
// ======================================================== // ========================================================
// Reticle // Reticle
// ======================================================== // ========================================================
const loader = new THREE.GLTFLoader(); const loader = new GLTFLoader();
loader.load( loader.load(
"https://immersive-web.github.io/webxr-samples/media/gltf/reticle/reticle.gltf", "https://immersive-web.github.io/webxr-samples/media/gltf/reticle/reticle.gltf",
(gltf) => { (gltf) => {
reticle = gltf.scene; reticle = gltf.scene;
reticle.visible = false; reticle.visible = false;
scene.add(reticle); scene.add(reticle);
}, },
undefined,
(error) => {
console.error("Fehler beim Laden des Reticles:", error);
},
); );
// ======================================================== // ========================================================
...@@ -1188,15 +1201,20 @@ async function activateXR(sceneData = null) { ...@@ -1188,15 +1201,20 @@ async function activateXR(sceneData = null) {
requiredFeatures: ["hit-test"], requiredFeatures: ["hit-test"],
}); });
currentSession.updateRenderState({ // Let Three.js manage the XR render state / framebuffer.
baseLayer: new XRWebGLLayer(currentSession, gl), await renderer.xr.setSession(currentSession);
});
const referenceSpace = renderer.xr.getReferenceSpace();
const referenceSpace = await currentSession.requestReferenceSpace("local"); if (!referenceSpace) {
throw new Error("XR reference space konnte nicht erstellt werden.");
}
const viewerSpace = await currentSession.requestReferenceSpace("viewer"); const viewerSpace =
await currentSession.requestReferenceSpace("viewer");
const hitTestSource = await currentSession.requestHitTestSource({ const hitTestSource =
await currentSession.requestHitTestSource({
space: viewerSpace, space: viewerSpace,
}); });
...@@ -1234,53 +1252,70 @@ async function activateXR(sceneData = null) { ...@@ -1234,53 +1252,70 @@ async function activateXR(sceneData = null) {
navigator.geolocation.getCurrentPosition( navigator.geolocation.getCurrentPosition(
(position) => { (position) => {
geoLocation = { geoLocation = {
latitude: roundTo(position.coords.latitude, 5), latitude: window.roundTo(position.coords.latitude, 5),
longitude: window.roundTo(position.coords.longitude, 5),
longitude: roundTo(position.coords.longitude, 5),
}; };
console.log("GeoLocation: " + JSON.stringify(geoLocation)); console.log(
"GeoLocation: " + JSON.stringify(geoLocation)
);
// ================================================= // =================================================
// Load saved scene models // Load saved scene models
// ================================================= // =================================================
if (sceneData) { if (sceneData && Array.isArray(sceneData.models)) {
sceneData.models.forEach((model) => { sceneData.models.forEach((model) => {
if (model.name) { if (model.name) {
const modelDefinition = Object.values(models).find( const modelDefinition =
(m) => model.name === m.name, Object.values(models).find(
(m) => model.name === m.name
); );
if (!modelDefinition) { if (!modelDefinition) {
console.error("Modell nicht gefunden:", model.name); console.error(
"Modell nicht gefunden:",
model.name
);
return; return;
} }
const filePath = modelDefinition.file; const filePath = modelDefinition.file;
const { x, z } = leafletToThree(model.lat, model.lng); // ar_overviewmap.js is loaded before user interaction,
// and exposes this conversion function on window.
const coordinates =
window.leafletToThree(model.lat, model.lng);
const positionVector = new THREE.Vector3(x, model.position.y, z); const positionVector =
new THREE.Vector3(
coordinates.x,
model.position.y,
coordinates.z
);
placeModel(filePath, positionVector, (placed) => { placeModel(
filePath,
positionVector,
(placed) => {
if (model.rotation) { if (model.rotation) {
placed.rotation._x = model.rotation._x; placed.rotation.set(
model.rotation._x ?? model.rotation.x ?? 0,
placed.rotation._y = model.rotation._y; model.rotation._y ?? model.rotation.y ?? 0,
model.rotation._z ?? model.rotation.z ?? 0
placed.rotation._z = model.rotation._z; );
} }
if (model.scale) { if (model.scale) {
placed.scale.x = model.scale.x; placed.scale.set(
model.scale.x,
placed.scale.y = model.scale.y; model.scale.y,
model.scale.z
placed.scale.z = model.scale.z; );
} }
}); }
);
} }
}); });
} }
...@@ -1300,61 +1335,47 @@ async function activateXR(sceneData = null) { ...@@ -1300,61 +1335,47 @@ async function activateXR(sceneData = null) {
}, },
); );
} }
// ======================================================== // ========================================================
// XR render loop // Modern Three.js XR render loop
// ======================================================== // ========================================================
currentSession.requestAnimationFrame(function onXRFrame(time, frame) { renderer.setAnimationLoop((time, frame) => {
currentSession.requestAnimationFrame(onXRFrame); if (!frame) {
return;
gl.bindFramebuffer( }
gl.FRAMEBUFFER,
currentSession.renderState.baseLayer.framebuffer,
);
const pose = frame.getViewerPose(referenceSpace);
if (pose) {
const view = pose.views[0];
const viewport = currentSession.renderState.baseLayer.getViewport(view);
renderer.setSize(viewport.width, viewport.height);
camera.matrix.fromArray(view.transform.matrix);
camera.projectionMatrix.fromArray(view.projectionMatrix);
camera.updateMatrixWorld(true);
// ================================================= // ======================================================
// Hit testing // Hit testing
// ================================================= // ======================================================
const hitTestResults = frame.getHitTestResults(hitTestSource); const hitTestResults =
frame.getHitTestResults(hitTestSource);
if (hitTestResults.length > 0) { if (hitTestResults.length > 0) {
const hitPose = hitTestResults[0].getPose(referenceSpace); const hitPose =
hitTestResults[0].getPose(referenceSpace);
if (hitPose && reticle) {
reticle.visible = true; reticle.visible = true;
reticle.position.set( reticle.position.set(
hitPose.transform.position.x, hitPose.transform.position.x,
hitPose.transform.position.y, hitPose.transform.position.y,
hitPose.transform.position.z, hitPose.transform.position.z,
); );
reticle.updateMatrixWorld(true); reticle.updateMatrixWorld(true);
} }
} else if (reticle) {
reticle.visible = false;
}
// ================================================= // ======================================================
// Render AR scene // Render AR scene
// ================================================= // ======================================================
renderer.render(scene, camera); renderer.render(scene, camera);
}
}); });
} }
...@@ -1395,3 +1416,37 @@ function playButtonSound() { ...@@ -1395,3 +1416,37 @@ function playButtonSound() {
}, 200); }, 200);
} }
} }
window.selectModel = selectModel;
window.updateRotation = updateRotation;
window.updateScale = updateScale;
window.updateMoveDelta = updateMoveDelta;
window.moveModelDynamic = moveModelDynamic;
window.closeDynamicMenu = closeDynamicMenu;
window.roundTo = window.roundTo;
/* ============================================================
GLOBAL API BRIDGE
------------------------------------------------------------
ES modules have their own scope. The existing HTML UI uses
inline onclick handlers, so expose the existing application
functions explicitly on window.
============================================================ */
window.showMenu = showMenu;
window.openRotationMenu = openRotationMenu;
window.openScaleMenu = openScaleMenu;
window.openMoveMenu = openMoveMenu;
window.deleteModel = deleteModel;
window.completeEditing = completeEditing;
window.confirmDelete = confirmDelete;
window.exitAR = exitAR;
window.confirmExit = confirmExit;
window.closeInfoDialog = closeInfoDialog;
window.getAllPlacedModels = getAllPlacedModels;
window.activateXR = activateXR;
window.getXRRenderCamera = () =>
xrRenderer && xrRenderer.xr.isPresenting
? xrRenderer.xr.getCamera(camera)
: camera;
import * as THREE from "three";
let init = false; let init = false;
let mymap; let mymap;
let userIcon; let userIcon;
...@@ -98,7 +100,7 @@ function init_map() { ...@@ -98,7 +100,7 @@ function init_map() {
// Add currently placed models to map // Add currently placed models to map
// ======================================================== // ========================================================
const models = getAllPlacedModels(); const models = window.getAllPlacedModels();
models.forEach((model) => { models.forEach((model) => {
const { lat, lng } = threeToLeaflet(model.position.x, model.position.z); const { lat, lng } = threeToLeaflet(model.position.x, model.position.z);
...@@ -210,7 +212,12 @@ function updateMap() { ...@@ -210,7 +212,12 @@ function updateMap() {
} }
// PERFORMANCE: Reuse the same Vector3 object. // PERFORMANCE: Reuse the same Vector3 object.
camera.getWorldPosition(cameraPosition); const activeCamera =
typeof window.getXRRenderCamera === "function"
? window.getXRRenderCamera()
: camera;
activeCamera.getWorldPosition(cameraPosition);
// PERFORMANCE: Do not update Leaflet if the user // PERFORMANCE: Do not update Leaflet if the user
// has not moved. // has not moved.
...@@ -323,3 +330,11 @@ function roundTo(n, digits) { ...@@ -323,3 +330,11 @@ function roundTo(n, digits) {
return parseFloat(n); return parseFloat(n);
} }
/* Expose map functions needed by the other application modules. */
window.init_map = init_map;
window.centerOnPlan = centerOnPlan;
window.threeToLeaflet = threeToLeaflet;
window.leafletToThree = leafletToThree;
window.roundTo = roundTo;
...@@ -190,7 +190,7 @@ function showStartScreen() { ...@@ -190,7 +190,7 @@ function showStartScreen() {
predefinedButton2 = null; predefinedButton2 = null;
// Start AR // Start AR
activateXR(sceneData); window.window.activateXR(sceneData);
}; };
/* ========================================================== /* ==========================================================
...@@ -198,7 +198,7 @@ function showStartScreen() { ...@@ -198,7 +198,7 @@ function showStartScreen() {
========================================================== */ ========================================================== */
loadButton.onclick = () => { loadButton.onclick = () => {
loadSceneFromFile((data, fileName) => { window.window.loadSceneFromFile((data, fileName) => {
if (data && fileName) { if (data && fileName) {
sceneData = data; sceneData = data;
sceneFileName = fileName; sceneFileName = fileName;
......
...@@ -9,8 +9,15 @@ ...@@ -9,8 +9,15 @@
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<script src="https://unpkg.com/three@0.126.0/build/three.js"></script> <!-- Three.js (modern ES module setup) -->
<script src="https://unpkg.com/three@0.126.0/examples/js/loaders/GLTFLoader.js"></script> <script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.186.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.186.0/examples/jsm/"
}
}
</script>
</head> </head>
<body> <body>
...@@ -299,7 +306,7 @@ ...@@ -299,7 +306,7 @@
============================================================ --> ============================================================ -->
<div id="app-version"> <div id="app-version">
v0.1.3 v186.0.1
</div> </div>
...@@ -307,21 +314,22 @@ ...@@ -307,21 +314,22 @@
JAVASCRIPT JAVASCRIPT
============================================================ --> ============================================================ -->
<script src="ar_start.js"></script> <!-- Debug console loads first so it can capture module errors/logs -->
<script src="ar_main.js"></script>
<script src="ar_debug_console.js"></script> <script src="ar_debug_console.js"></script>
<!-- Application modules -->
<script type="module" src="ar_main.js"></script>
<script type="module" src="ar_overviewmap.js"></script>
<script type="module" src="ar_download.js"></script>
<script type="module" src="ar_start.js"></script>
<link <link
rel="stylesheet" rel="stylesheet"
href="https://unpkg.com/leaflet/dist/leaflet.css" /> href="https://unpkg.com/leaflet/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script> <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script src="ar_overviewmap.js"></script>
<script src="ar_download.js"></script>
<!-- ============================================================ <!-- ============================================================
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment