Commit de77f40d authored by Stoll's avatar Stoll
Browse files

Refactoring

Added Script for ADB setup
parent 7d1e0011
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
"dev": "vite", "dev": "vite",
"build": "tsc -b && vite build", "build": "tsc -b && vite build",
"lint": "eslint .", "lint": "eslint .",
"preview": "vite preview" "preview": "vite preview",
"adb": "adb reverse tcp:8081 tcp:8081"
}, },
"dependencies": { "dependencies": {
"react": "^19.1.1", "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"; ...@@ -5,7 +5,20 @@ import { XRButton } from "three/examples/jsm/webxr/XRButton";
import { BlockManager } from "./BlockManager"; // manages placed 3D objects in the scene import { BlockManager } from "./BlockManager"; // manages placed 3D objects in the scene
import { Cube } from "../model/Cube"; // custom class for a simple cube import { Cube } from "../model/Cube"; // custom class for a simple cube
import { GLTFModel } from "../model/GLTFModel"; // custom loader for .glb 3D models 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 = () => { export const XRRenderer: React.FC = () => {
...@@ -24,50 +37,25 @@ export const XRRenderer: React.FC = () => { ...@@ -24,50 +37,25 @@ export const XRRenderer: React.FC = () => {
// --- 1️⃣ Scene setup --- // --- 1️⃣ Scene setup ---
const scene = new THREE.Scene(); const scene = new THREE.Scene();
scene.background = null; // WebXR automatically shows camera feed behind 3D scene setSceneBackground(scene);
// Camera: standard perspective camera const camera = createCamera();
const camera = new THREE.PerspectiveCamera( const renderer = createRenderer();
70, // field of view (in degrees)
window.innerWidth / window.innerHeight, // aspect ratio addLightToScene(scene);
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
mountRef.current.appendChild(renderer.domElement); // attach to our div 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 pmremGenerator = new THREE.PMREMGenerator( new THREE.WebGLRenderer() );
const light = new THREE.AmbientLight(0xffffff, 0.5); // soft white light scene.environment = pmremGenerator.fromScene(new RoomEnvironment(), 0.04).texture;
scene.add(light);
const button = createARButton(renderer, overlayRef);
mountRef.current.appendChild(button);
// --- 4️⃣ Block manager (handles placed 3D objects) --- // --- 4️⃣ Block manager (handles placed 3D objects) ---
const blockManager = new BlockManager(scene); const blockManager = new BlockManager(scene);
const reticle = createPlacementRing(scene, reticleRef);
// --- 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
// --- 6️⃣ WebXR hit-test setup (detect real-world planes) --- // --- 6️⃣ WebXR hit-test setup (detect real-world planes) ---
let hitTestSource: XRHitTestSource | null = null; let hitTestSource: XRHitTestSource | null = null;
...@@ -148,9 +136,9 @@ export const XRRenderer: React.FC = () => { ...@@ -148,9 +136,9 @@ export const XRRenderer: React.FC = () => {
if (name === "Cube") { if (name === "Cube") {
objectToAdd = new Cube(position); objectToAdd = new Cube(position);
} else if (name === "Watermill") { } 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") { } else if (name === "Tree") {
objectToAdd = new GLTFModel("/tree.glb", position, "/Textures/variation-a.png"); objectToAdd = new GLTFModel("/tree.glb", position, "/Textures/colormap.png");
} else { } else {
objectToAdd = new Cube(position); // fallback objectToAdd = new Cube(position); // fallback
} }
......
...@@ -26,9 +26,10 @@ export class GLTFModel implements IRenderable { ...@@ -26,9 +26,10 @@ export class GLTFModel implements IRenderable {
} }
const textureLoader = new THREE.TextureLoader(); const textureLoader = new THREE.TextureLoader();
const texture : Texture = textureLoader.load("/Textures/variation-a.png"); const texture : Texture = textureLoader.load("/Textures/variation-a.png", (texture) => {
texture.flipY = false;
texture.colorSpace = THREE.SRGBColorSpace; texture.colorSpace = THREE.SRGBColorSpace;
});
const loader = new GLTFLoader(); const loader = new GLTFLoader();
loader.load( loader.load(
...@@ -41,7 +42,7 @@ export class GLTFModel implements IRenderable { ...@@ -41,7 +42,7 @@ export class GLTFModel implements IRenderable {
textureUrl, textureUrl,
(texture) => { (texture) => {
//texture.encoding = THREE.sRGBEncoding; //texture.encoding = THREE.sRGBEncoding;
//texture.flipY = false;
gltf.scene.traverse((child) => { gltf.scene.traverse((child) => {
if ((child as THREE.Mesh).isMesh) { if ((child as THREE.Mesh).isMesh) {
const mesh = child as THREE.Mesh; const mesh = child as THREE.Mesh;
...@@ -65,6 +66,7 @@ export class GLTFModel implements IRenderable { ...@@ -65,6 +66,7 @@ export class GLTFModel implements IRenderable {
); );
} else { } else {
// No texture: just add model // No texture: just add model
alert("GLB file not found: " + url);
this.mesh.add(gltf.scene); this.mesh.add(gltf.scene);
gltf.scene.scale.set(0.5, 0.5, 0.5); gltf.scene.scale.set(0.5, 0.5, 0.5);
if (onLoad) onLoad(); 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