refactor: nds as a 3d object

This commit is contained in:
2025-12-13 17:28:23 +01:00
parent 8d45b76944
commit 1a82f3c8d0
4 changed files with 76 additions and 82 deletions

72
src/nds.ts Normal file
View File

@@ -0,0 +1,72 @@
import * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
export class NDS extends THREE.Object3D {
topScreenMesh: THREE.Mesh | undefined;
bottomScreenMesh: THREE.Mesh | undefined;
public constructor(camera: THREE.Camera, domElement: HTMLCanvasElement) {
super();
const loader = new GLTFLoader();
// load model
loader.load("/nintendo-ds/scene.gltf", ({ scene: model }) => {
model.scale.set(50, 50, 50);
// find top and bottom screens
model.traverse((child) => {
if (child instanceof THREE.Mesh) {
const material = child.material as THREE.Material;
if (material.name?.includes("screen_up")) {
this.topScreenMesh = child;
} else if (material.name?.includes("screen_down")) {
this.bottomScreenMesh = child;
}
}
});
if (!this.topScreenMesh) throw new Error(`Missing top screen`);
if (!this.bottomScreenMesh) throw new Error(`Missing bottom screen`);
const { topScreenMesh, bottomScreenMesh } = this;
domElement.addEventListener("mousemove", (event) => {
const rect = 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) {
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);
x;
y;
}
}
});
super.add(model);
});
}
}