Commit d69bf271 authored by Alfakhori's avatar Alfakhori
Browse files

v0.2.0

parent 9ecd2076
Pipeline #12490 passed with stage
in 26 seconds
import { showInfoDialog } from './ar_main.js';
function downloadScene() {
const placedModels = window.getAllPlacedModels().map(model => {
const { lat, lng } = window.threeToLeaflet(model.position.x, model.position.z);
const placedModels = getAllPlacedModels().map(model => {
const { lat, lng } = threeToLeaflet(model.position.x, model.position.z);
return {
name: model.modelConfig.name,
position: model.position,
......@@ -18,7 +17,6 @@ function downloadScene() {
return;
}
const geoLocation = window.getGeoLocation();
if (!geoLocation) {
console.log("Standort nicht geladen");
showInfoDialog("Ihr Standort wurde noch nicht geladen");
......@@ -73,7 +71,3 @@ function loadSceneFromFile(loadedData) {
});
fileInput.click();
}
\ No newline at end of file
/* 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 */
/* ========================= */
......@@ -9,14 +6,13 @@ let selectedPlacedModel = null;
let currentSession = null;
let reticle = null;
let scene, camera;
let xrRenderer = null;
let geoLocation;
const modelCache = new Map();
// PERFORMANCE: Reuse one GLTFLoader instead of creating
// a new loader every time a model is placed.
const gltfLoader = new GLTFLoader();
const gltfLoader = new THREE.GLTFLoader();
const menus = [
'menu-bar',
......@@ -294,7 +290,7 @@ function closeDynamicMenu() {
}
export function showInfoDialog(message) {
function showInfoDialog(message) {
const infoDialog =
document.getElementById(
......@@ -518,14 +514,9 @@ function selectModelFromScene(event) {
new THREE.Raycaster();
const rayCamera =
xrRenderer && xrRenderer.xr.isPresenting
? xrRenderer.xr.getCamera(camera)
: camera;
raycaster.setFromCamera(
mouse,
rayCamera
camera
);
......@@ -1123,64 +1114,78 @@ function closeMapDialog() {
async function activateXR(sceneData = null) {
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
// Keep the original WebXR rendering architecture.
// Three.js r186 is used only as the renderer/scene library;
// WebXR session, hit-test source, framebuffer and camera pose
// are still controlled explicitly as in the working r126 version.
const gl = canvas.getContext("webgl", {
xrCompatible: true,
alpha: true,
antialias: true,
});
if (!gl) {
throw new Error("WebGL konnte nicht initialisiert werden.");
}
const renderer = new THREE.WebGLRenderer({
alpha: true,
canvas,
context: gl,
antialias: true,
});
renderer.autoClear = false;
xrRenderer = renderer;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera();
camera.matrixAutoUpdate = false;
// ========================================================
// AR lighting
// ========================================================
// Soft overall illumination
const ambientLight = new THREE.AmbientLight(0xffffff, 2.5);
scene.add(ambientLight);
// Sky/ground illumination
const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x888888, 1.5);
scene.add(hemisphereLight);
// Directional light for shadows and form
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
directionalLight.position.set(10, 20, 10);
scene.add(directionalLight);
// ========================================================
// Reticle
const loader = new GLTFLoader();
// ========================================================
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);
},
undefined,
(error) => console.error("Fehler beim Laden des Reticles:", error)
);
// WebXR session
// ========================================================
// Start WebXR AR session
// ========================================================
currentSession = await navigator.xr.requestSession("immersive-ar", {
requiredFeatures: ["hit-test"],
optionalFeatures: ["dom-overlay"],
domOverlay: { root: document.body },
domOverlay: {
root: document.body,
},
requiredFeatures: ["hit-test"],
});
currentSession.updateRenderState({
......@@ -1188,131 +1193,168 @@ async function activateXR(sceneData = null) {
});
const referenceSpace = await currentSession.requestReferenceSpace("local");
const viewerSpace = await currentSession.requestReferenceSpace("viewer");
const hitTestSource = await currentSession.requestHitTestSource({
space: viewerSpace,
});
// ========================================================
// Show main menu
// ========================================================
document.getElementById("menu-bar").style.display = "flex";
// ========================================================
// AR session ended
// Reload the complete website
// ========================================================
currentSession.addEventListener("end", () => {
console.log("AR session ended");
// Completely reload the website.
// This resets the AR canvas, menus, scene, map,
// variables, and all other application state.
window.location.reload();
});
// ========================================================
// Select objects in AR
// ========================================================
canvas.addEventListener("pointerdown", selectModelFromScene);
// ========================================================
// Geolocation
// ========================================================
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
geoLocation = {
latitude: window.roundTo(position.coords.latitude, 5),
longitude: window.roundTo(position.coords.longitude, 5),
latitude: roundTo(position.coords.latitude, 5),
longitude: roundTo(position.coords.longitude, 5),
};
console.log("GeoLocation: " + JSON.stringify(geoLocation));
if (sceneData && Array.isArray(sceneData.models)) {
sceneData.models.forEach((model) => {
if (!model.name) return;
// =================================================
// Load saved scene models
// =================================================
if (sceneData) {
sceneData.models.forEach((model) => {
if (model.name) {
const modelDefinition = Object.values(models).find(
(m) => model.name === m.name
(m) => model.name === m.name,
);
if (!modelDefinition) {
console.error("Modell nicht gefunden:", model.name);
return;
}
const { x, z } = window.leafletToThree(model.lat, model.lng);
const positionVector = new THREE.Vector3(
x,
model.position?.y ?? 0,
z
);
const filePath = modelDefinition.file;
const { x, z } = leafletToThree(model.lat, model.lng);
const positionVector = new THREE.Vector3(x, model.position.y, z);
placeModel(modelDefinition.file, positionVector, (placed) => {
placeModel(filePath, positionVector, (placed) => {
if (model.rotation) {
placed.rotation.set(
model.rotation._x ?? model.rotation.x ?? 0,
model.rotation._y ?? model.rotation.y ?? 0,
model.rotation._z ?? model.rotation.z ?? 0
);
placed.rotation._x = model.rotation._x;
placed.rotation._y = model.rotation._y;
placed.rotation._z = model.rotation._z;
}
if (model.scale) {
placed.scale.set(
model.scale.x,
model.scale.y,
model.scale.z
);
placed.scale.x = model.scale.x;
placed.scale.y = model.scale.y;
placed.scale.z = model.scale.z;
}
});
}
});
}
},
(error) => {
console.error("Fehler bei der Geolokalisierung:", error);
console.error(
"Fehler bei der Geolokalisierung:",
JSON.stringify(error),
);
},
{
enableHighAccuracy: true,
maximumAge: 2000,
timeout: 5000,
}
},
);
}
// ========================================================
// XR render loop
// ========================================================
// Keep the original explicit XR frame loop.
currentSession.requestAnimationFrame(function onXRFrame(time, frame) {
currentSession.requestAnimationFrame(onXRFrame);
const session = frame.session;
const baseLayer = session.renderState.baseLayer;
if (!baseLayer) return;
gl.bindFramebuffer(gl.FRAMEBUFFER, baseLayer.framebuffer);
gl.bindFramebuffer(
gl.FRAMEBUFFER,
currentSession.renderState.baseLayer.framebuffer,
);
const pose = frame.getViewerPose(referenceSpace);
if (!pose) return;
// This application uses one camera/view, as in the original version.
if (pose) {
const view = pose.views[0];
const viewport = baseLayer.getViewport(view);
if (!viewport) return;
renderer.setViewport(
viewport.x,
viewport.y,
viewport.width,
viewport.height
);
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
// =================================================
const hitTestResults = frame.getHitTestResults(hitTestSource);
if (hitTestResults.length > 0) {
const hitPose = hitTestResults[0].getPose(referenceSpace);
if (hitPose && reticle) {
reticle.visible = true;
reticle.position.set(
hitPose.transform.position.x,
hitPose.transform.position.y,
hitPose.transform.position.z
hitPose.transform.position.z,
);
reticle.updateMatrixWorld(true);
}
} else if (reticle) {
reticle.visible = false;
}
// =================================================
// Render AR scene
// =================================================
renderer.render(scene, camera);
}
});
}
......@@ -1353,34 +1395,3 @@ function playButtonSound() {
}, 200);
}
}
\ No newline at end of file
window.selectModel = selectModel;
window.updateRotation = updateRotation;
window.updateScale = updateScale;
window.updateMoveDelta = updateMoveDelta;
window.moveModelDynamic = moveModelDynamic;
window.closeDynamicMenu = closeDynamicMenu;
/* ============================================================
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 = () => camera;
window.getGeoLocation = () => geoLocation;
import * as THREE from "three";
let init = false;
let mymap;
let userIcon;
......@@ -100,7 +98,7 @@ function init_map() {
// Add currently placed models to map
// ========================================================
const models = window.getAllPlacedModels();
const models = getAllPlacedModels();
models.forEach((model) => {
const { lat, lng } = threeToLeaflet(model.position.x, model.position.z);
......@@ -212,12 +210,7 @@ function updateMap() {
}
// PERFORMANCE: Reuse the same Vector3 object.
const activeCamera =
typeof window.getXRRenderCamera === "function"
? window.getXRRenderCamera()
: camera;
activeCamera.getWorldPosition(cameraPosition);
camera.getWorldPosition(cameraPosition);
// PERFORMANCE: Do not update Leaflet if the user
// has not moved.
......@@ -330,11 +323,3 @@ function roundTo(n, digits) {
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;
import { activateXR } from './ar_main.js';
import { loadSceneFromFile } from './ar_download.js';
/* ========================= */
/* DEBUGGING UND START */
/* ========================= */
......@@ -192,7 +190,7 @@ function showStartScreen() {
predefinedButton2 = null;
// Start AR
window.window.activateXR(sceneData);
activateXR(sceneData);
};
/* ==========================================================
......@@ -200,7 +198,7 @@ function showStartScreen() {
========================================================== */
loadButton.onclick = () => {
window.window.loadSceneFromFile((data, fileName) => {
loadSceneFromFile((data, fileName) => {
if (data && fileName) {
sceneData = data;
sceneFileName = fileName;
......
......@@ -9,15 +9,8 @@
<link rel="stylesheet" href="style.css">
<!-- Three.js (modern ES module setup) -->
<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>
<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>
......@@ -306,7 +299,7 @@
============================================================ -->
<div id="app-version">
v186.0.2
v0.2.0
</div>
......@@ -314,7 +307,10 @@
JAVASCRIPT
============================================================ -->
<!-- Debug console loads first so it can capture module errors/logs -->
<script src="ar_start.js"></script>
<script src="ar_main.js"></script>
<script src="ar_debug_console.js"></script>
<link
......@@ -323,13 +319,9 @@
<script src="https://unpkg.com/leaflet/dist/leaflet.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>
<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