Skip to content

Commit

Permalink
Merge branch 'fix-get-3d-point-bug' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
tsengyushiang committed May 2, 2024
2 parents b2ac499 + 5c875f9 commit d3c8e70
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 37 deletions.
93 changes: 68 additions & 25 deletions src/ThreeApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as THREE from "three";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import PathFinder from "./PathFinder";
import { TransformControls } from "three/addons/controls/TransformControls.js";

function interpolatePoints(pointsArray, numPoints) {
var interpolatedPoints = [];
Expand Down Expand Up @@ -77,14 +78,18 @@ function ThreeApp(canvas) {
0.1,
3
);
const agent = new THREE.Object3D();
const helper = new THREE.CameraHelper(firstPersonViewCamera);
scene.add(firstPersonViewCamera);
firstPersonViewCamera.position.set(0, 1, 0);
firstPersonViewCamera.rotateY(Math.PI);
agent.add(firstPersonViewCamera);
scene.add(agent);
scene.add(helper);
const setCamera = ([x, y, z], [lookAtX, lookAtY, lookAtZ]) => {
firstPersonViewCamera.position.set(x, y, z);
firstPersonViewCamera.lookAt(lookAtX, lookAtY, lookAtZ);
agent.position.set(x, y, z);
agent.lookAt(lookAtX, lookAtY, lookAtZ);
};
return { setCamera, firstPersonViewCamera };
return { setCamera, firstPersonViewCamera: agent };
})();

const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
Expand All @@ -95,6 +100,44 @@ function ThreeApp(canvas) {
camera.position.set(0, 10, 10);
controls.update();

const { getSensors, onSelectSensor } = (() => {
const transformControls = new TransformControls(camera, canvas);
scene.add(transformControls);
transformControls.addEventListener("dragging-changed", function (event) {
controls.enabled = !event.value;
});

const sensorGroup = new THREE.Group();
scene.add(sensorGroup);
const geometry = new THREE.SphereGeometry(0.5, 32, 16);
const material = new THREE.MeshPhongMaterial({
color: 0xff0000,
});

const sphere = new THREE.Mesh(geometry, material);
sensorGroup.add(sphere);

const getSensors = () => {};

const onSelectSensor = (event) => {
const mouse = new THREE.Vector2();
const rect = canvas.getBoundingClientRect();
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

// Set the raycaster position based on the mouse coordinates
raycaster.setFromCamera(mouse, camera);

// Check for intersections
const intersects = raycaster.intersectObjects(sensorGroup.children, true);
if (intersects.length > 0) {
transformControls.attach(intersects[0].object);
}
};

return { getSensors, onSelectSensor };
})();

const gridHelper = new THREE.GridHelper(20, 20);
scene.add(gridHelper);

Expand All @@ -117,36 +160,33 @@ function ThreeApp(canvas) {
});

const raycaster = new THREE.Raycaster();
const onFindPath = (event) => {
const getPointFromClick = (event) => {
const mouse = new THREE.Vector2();
const rect = canvas.getBoundingClientRect();
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

// Set the raycaster position based on the mouse coordinates
raycaster.setFromCamera(mouse, camera);

// Check for intersections
const intersects = raycaster.intersectObjects(scene.children, true);

const intersects = raycaster.intersectObject(navMesh, true);
if (intersects.length > 0) {
// Get the coordinates of the first intersection point
const { point } = intersects[0];
const path = pathFinder.getPathFromA2B(
firstPersonViewCamera.position,
point
);
if (!path) return null;

const refinePath = [
firstPersonViewCamera.position,
...path.map(({ x, y, z }) => new THREE.Vector3(x, y + 1, z)),
];

return interpolatePoints(refinePath, 20);
return intersects[0].point;
}
return null;
};
const findPathTo = (point) => {
const path = pathFinder.getPathFromA2B(
firstPersonViewCamera.position,
point
);
if (!path) return null;

const refinePath = [
firstPersonViewCamera.position,
...path.map(({ x, y, z }) => new THREE.Vector3(x, y, z)),
];

return interpolatePoints(refinePath, 20);
};

const animate = () => {
requestAnimationFrame(animate);
Expand All @@ -171,9 +211,12 @@ function ThreeApp(canvas) {

return {
resizeCanvas,
onFindPath,
getPointFromClick,
findPathTo,
setCamera,
setPath,
getSensors,
onSelectSensor,
};
}

Expand Down
55 changes: 43 additions & 12 deletions src/ThreeCanvas.jsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,67 @@
import React, { useEffect, useRef } from "react";
import React, { useEffect, useRef, useState } from "react";
import ThreeApp from "./ThreeApp";
const FullScreenCanvas = () => {
const [core, setCore] = useState(null);
const [isTeleport, setIsTeleport] = useState(true);
const canvasRef = useRef(null);

useEffect(() => {
const canvas = canvasRef.current;
const core = new ThreeApp(canvas);

core.setCamera([-3, 1, 5], [-3, 1, 4]);
const threeApp = new ThreeApp(canvas);
setCore(threeApp);
}, []);

useEffect(() => {
if (!core) return;
const canvas = canvasRef.current;
const onPointerUp = (e) => {
const path = core.onFindPath(e);
const point = core.getPointFromClick(e);

if (path) {
core.setPath(path);
if (isTeleport) {
if (point)
core.setCamera(
[point.x, point.y, point.z],
[point.x, point.y, point.z - 1]
);
return;
}

if (point) {
const path = core.findPathTo(point);

if (path) {
core.setCamera(
[path[0].x, path[0].y, path[0].z],
[path[1].x, path[1].y, path[1].z]
);
core.setPath(path);
}
}
};

window.addEventListener("resize", core.resizeCanvas);
canvas.addEventListener("pointerdown", core.onSelectSensor);
canvas.addEventListener("pointerup", onPointerUp);

return () => {
window.removeEventListener("resize", core.resizeCanvas);
canvas.addEventListener("pointerdown", core.onSelectSensor);
canvas.removeEventListener("pointerup", onPointerUp);
};
}, []);
}, [core, isTeleport]);

return (
<canvas
ref={canvasRef}
style={{ width: "100%", height: "100%", display: "block" }}
/>
<>
<div style={{ position: "absolute" }}>
<button onClick={() => setIsTeleport((prev) => !prev)}>
{isTeleport ? "click to teleport" : "click to find path"}
</button>
</div>
<canvas
ref={canvasRef}
style={{ width: "100%", height: "100%", display: "block" }}
/>
</>
);
};

Expand Down

0 comments on commit d3c8e70

Please sign in to comment.