feat: compute mouse position for each screen

This commit is contained in:
2025-12-13 17:00:42 +01:00
parent 285de91dd0
commit 8d45b76944
3 changed files with 75 additions and 0 deletions

View File

@@ -7,6 +7,7 @@
</head>
<body>
<div id="app"></div>
<div id="coord-display"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

View File

@@ -33,6 +33,23 @@ const nds = await loader.loadAsync("/nintendo-ds/scene.gltf");
nds.scene.scale.set(50, 50, 50);
scene.add(nds.scene);
let topScreenMesh: THREE.Mesh | undefined = undefined;
let bottomScreenMesh: THREE.Mesh | undefined = undefined;
nds.scene.traverse((child) => {
if (child instanceof THREE.Mesh) {
const material = child.material as THREE.Material;
if (material.name?.includes("screen_up")) {
topScreenMesh = child;
} else if (material.name?.includes("screen_down")) {
bottomScreenMesh = child;
}
}
});
if (!topScreenMesh) throw new Error(`Top screen mesh not found`);
if (!bottomScreenMesh) throw new Error(`Bottom screen mesh not found`);
// create light
const color = 0xffffff;
const intensity = 3;
@@ -44,6 +61,50 @@ directional.target = nds.scene;
directional.position.set(0, 100, 0);
scene.add(directional);
const coordDisplay = document.getElementById("coord-display")!;
renderer.domElement.addEventListener("mousemove", (event) => {
const rect = renderer.domElement.getBoundingClientRect();
const raycaster = new THREE.Raycaster();
raycaster.setFromCamera(
new THREE.Vector2(
((event.clientX - rect.left) / rect.width) * 2 - 1,
-((event.clientY - rect.top) / rect.height) * 2 + 1,
),
camera,
);
const intersects = raycaster.intersectObjects([
topScreenMesh!,
bottomScreenMesh!,
]);
if (intersects.length > 0) {
const intersection = intersects[0];
const mesh = intersection.object as THREE.Mesh;
const uv = intersection.uv;
if (uv) {
coordDisplay.hidden = false;
const x = Math.floor(uv.x * 256);
const y =
mesh === topScreenMesh
? Math.floor(uv.y * (1024 / 404) * 192)
: // invert coords only for bottom screen
Math.floor(192 - (1 - uv.y) * (1024 / 532) * 192);
const screenName = mesh === topScreenMesh ? "top" : "bottom";
coordDisplay.textContent = `${screenName} | pos: (${x}, ${y})`;
} else {
coordDisplay.hidden = true;
}
} else {
coordDisplay.hidden = true;
}
});
// main loop
renderer.setAnimationLoop(() => {
controls.update();

View File

@@ -1,3 +1,16 @@
body {
margin: 0;
}
#coord-display {
position: fixed;
top: 5px;
left: 5px;
color: white;
font-family: monospace;
font-size: 16px;
background-color: #000000;
padding: 10px;
pointer-events: none;
z-index: 1000;
}