Commit de77f40d authored by Stoll's avatar Stoll
Browse files

Refactoring

Added Script for ADB setup
parent 7d1e0011
......@@ -7,7 +7,8 @@
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
"preview": "vite preview",
"adb": "adb reverse tcp:8081 tcp:8081"
},
"dependencies": {
"react": "^19.1.1",
......
import {Mesh, Scene, WebGLRenderer} from "three";
import React from "react";
import * as THREE from "three";
export function setSceneBackground(scene: Scene) {
scene.background = null; // WebXR automatically shows camera feed behind 3D scene
}
export function createPlacementRing(scene: Scene, reticleRef: React.RefObject<Mesh | null>) {
// --- 5️⃣ Create reticle (green ring where we can place objects) ---
const reticleGeometry = new THREE.RingGeometry(0.1, 0.12, 32);
const reticleMaterial = new THREE.MeshBasicMaterial({color: 0x00ff00});
const reticle = new THREE.Mesh(reticleGeometry, reticleMaterial);
reticle.rotation.x = -Math.PI / 2; // lay flat on the ground
reticle.visible = false; // hidden until we detect a plane
scene.add(reticle);
reticleRef.current = reticle; // save for later reference
return reticle;
}
export function createRenderer() {
// Renderer: where 3D things are drawn
const renderer = new THREE.WebGLRenderer({
antialias: true, // smooth edges
alpha: true, // allow transparency (so camera feed is visible)
preserveDrawingBuffer: true, // so we can take screenshots later
});
renderer.setSize(window.innerWidth, window.innerHeight);
enableXR(renderer);
return renderer;
}
export function createCamera() {
// Camera: standard perspective camera
const camera = new THREE.PerspectiveCamera(
70, // field of view (in degrees)
window.innerWidth / window.innerHeight, // aspect ratio
0.01, // near clipping plane
20 // far clipping plane
);
return camera;
}
export function addLightToScene(scene: Scene) {
// --- 3️⃣ Add simple lighting ---
const light = new THREE.AmbientLight(0xffffff, 0.5); // soft white light
scene.add(light);
}
function enableXR(renderer: WebGLRenderer) {
renderer.xr.enabled = true; // turn on WebXR support
renderer.xr.setReferenceSpaceType("local-floor"); // reference at floor level
}
\ No newline at end of file
......@@ -5,7 +5,20 @@ import { XRButton } from "three/examples/jsm/webxr/XRButton";
import { BlockManager } from "./BlockManager"; // manages placed 3D objects in the scene
import { Cube } from "../model/Cube"; // custom class for a simple cube
import { GLTFModel } from "../model/GLTFModel"; // custom loader for .glb 3D models
import { ARBottomBar } from "./ARBottomBar"; // bottom UI for selecting objects
import { ARBottomBar } from "./ARBottomBar";
import {RoomEnvironment} from "three/examples/jsm/environments/RoomEnvironment";
import {addLightToScene, createCamera, createPlacementRing, createRenderer, setSceneBackground} from "./Setup.ts"; // bottom UI for selecting objects
function createARButton(renderer: WebGLRenderer, overlayRef: React.RefObject<HTMLDivElement>) {
// --- 2️⃣ Create AR Button (to enter AR mode) ---
const button = XRButton.createButton(renderer, {
requiredFeatures: ["hit-test", "dom-overlay"], // needed to detect planes + show UI overlay
optionalFeatures: ["local-floor"], // extra feature (some devices only)
domOverlay: {root: overlayRef.current}, // attach HTML overlay (UI)
});
return button;
}
export const XRRenderer: React.FC = () => {
......@@ -24,50 +37,25 @@ export const XRRenderer: React.FC = () => {
// --- 1️⃣ Scene setup ---
const scene = new THREE.Scene();
scene.background = null; // WebXR automatically shows camera feed behind 3D scene
// Camera: standard perspective camera
const camera = new THREE.PerspectiveCamera(
70, // field of view (in degrees)
window.innerWidth / window.innerHeight, // aspect ratio
0.01, // near clipping plane
20 // far clipping plane
);
// Renderer: where 3D things are drawn
const renderer = new THREE.WebGLRenderer({
antialias: true, // smooth edges
alpha: true, // allow transparency (so camera feed is visible)
preserveDrawingBuffer: true, // so we can take screenshots later
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.xr.enabled = true; // turn on WebXR support
renderer.xr.setReferenceSpaceType("local-floor"); // reference at floor level
setSceneBackground(scene);
const camera = createCamera();
const renderer = createRenderer();
addLightToScene(scene);
mountRef.current.appendChild(renderer.domElement); // attach to our div
// --- 2️⃣ Create AR Button (to enter AR mode) ---
const button = XRButton.createButton(renderer, {
requiredFeatures: ["hit-test", "dom-overlay"], // needed to detect planes + show UI overlay
optionalFeatures: ["local-floor"], // extra feature (some devices only)
domOverlay: { root: overlayRef.current }, // attach HTML overlay (UI)
});
mountRef.current.appendChild(button);
// --- 3️⃣ Add simple lighting ---
const light = new THREE.AmbientLight(0xffffff, 0.5); // soft white light
scene.add(light);
const pmremGenerator = new THREE.PMREMGenerator( new THREE.WebGLRenderer() );
scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture;
const button = createARButton(renderer, overlayRef);
mountRef.current.appendChild(button);
// --- 4️⃣ Block manager (handles placed 3D objects) ---
const blockManager = new BlockManager(scene);
// --- 5️⃣ Create reticle (green ring where we can place objects) ---
const reticleGeometry = new THREE.RingGeometry(0.1, 0.12, 32);
const reticleMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const reticle = new THREE.Mesh(reticleGeometry, reticleMaterial);
reticle.rotation.x = -Math.PI / 2; // lay flat on the ground
reticle.visible = false; // hidden until we detect a plane
scene.add(reticle);
reticleRef.current = reticle; // save for later reference
const reticle = createPlacementRing(scene, reticleRef);
// --- 6️⃣ WebXR hit-test setup (detect real-world planes) ---
let hitTestSource: XRHitTestSource | null = null;
......@@ -148,9 +136,9 @@ export const XRRenderer: React.FC = () => {
if (name === "Cube") {
objectToAdd = new Cube(position);
} else if (name === "Watermill") {
objectToAdd = new GLTFModel("/watermill.glb", position, "/Textures/variation-a.png");
objectToAdd = new GLTFModel("/watermill.glb", position, "/Textures/colormap.png");
} else if (name === "Tree") {
objectToAdd = new GLTFModel("/tree.glb", position, "/Textures/variation-a.png");
objectToAdd = new GLTFModel("/tree.glb", position, "/Textures/colormap.png");
} else {
objectToAdd = new Cube(position); // fallback
}
......
......@@ -26,9 +26,10 @@ export class GLTFModel implements IRenderable {
}
const textureLoader = new THREE.TextureLoader();
const texture : Texture = textureLoader.load("/Textures/variation-a.png");
texture.colorSpace = THREE.SRGBColorSpace;
const texture : Texture = textureLoader.load("/Textures/variation-a.png", (texture) => {
texture.flipY = false;
texture.colorSpace = THREE.SRGBColorSpace;
});
const loader = new GLTFLoader();
loader.load(
......@@ -41,7 +42,7 @@ export class GLTFModel implements IRenderable {
textureUrl,
(texture) => {
//texture.encoding = THREE.sRGBEncoding;
//texture.flipY = false;
gltf.scene.traverse((child) => {
if ((child as THREE.Mesh).isMesh) {
const mesh = child as THREE.Mesh;
......@@ -65,6 +66,7 @@ export class GLTFModel implements IRenderable {
);
} else {
// No texture: just add model
alert("GLB file not found: " + url);
this.mesh.add(gltf.scene);
gltf.scene.scale.set(0.5, 0.5, 0.5);
if (onLoad) onLoad();
......
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