refactor: nds as a 3d object
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="coord-display"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
72
src/main.ts
72
src/main.ts
@@ -1,8 +1,8 @@
|
||||
import "./style.css";
|
||||
|
||||
import * as THREE from "three";
|
||||
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
|
||||
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
||||
import { NDS } from "./nds";
|
||||
|
||||
// initialize scene
|
||||
const scene = new THREE.Scene();
|
||||
@@ -27,28 +27,8 @@ const handleResize = () => {
|
||||
window.addEventListener("resize", handleResize, false);
|
||||
handleResize();
|
||||
|
||||
// load nds model
|
||||
const loader = new GLTFLoader();
|
||||
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`);
|
||||
const nds = new NDS(camera, renderer.domElement);
|
||||
scene.add(nds);
|
||||
|
||||
// create light
|
||||
const color = 0xffffff;
|
||||
@@ -57,54 +37,10 @@ const ambient = new THREE.AmbientLight(color, intensity);
|
||||
scene.add(ambient);
|
||||
|
||||
const directional = new THREE.DirectionalLight(color, intensity);
|
||||
directional.target = nds.scene;
|
||||
directional.target = nds;
|
||||
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();
|
||||
|
||||
72
src/nds.ts
Normal file
72
src/nds.ts
Normal 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,3 @@
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user