Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
HFT-informatics-weekend
AR - Urban Planner
Commits
de77f40d
Commit
de77f40d
authored
Oct 12, 2025
by
Stoll
Browse files
Refactoring
Added Script for ADB setup
parent
7d1e0011
Changes
5
Show whitespace changes
Inline
Side-by-side
webxr-cube/package.json
View file @
de77f40d
...
@@ -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"
,
...
...
webxr-cube/public/Textures/
variation-a
.png
→
webxr-cube/public/Textures/
colormap
.png
View file @
de77f40d
File moved
webxr-cube/src/components/Setup.ts
0 → 100644
View file @
de77f40d
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
webxr-cube/src/components/XRRenderer.tsx
View file @
de77f40d
...
@@ -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
}
}
...
...
webxr-cube/src/model/GLTFModel.ts
View file @
de77f40d
...
@@ -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
();
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment