diff --git a/client/src/components/HitTestView.tsx b/client/src/components/HitTestView.tsx index ff328de..6182f10 100644 --- a/client/src/components/HitTestView.tsx +++ b/client/src/components/HitTestView.tsx @@ -7,10 +7,10 @@ export const HitTestView = observer(function () {
{
- state.hitTest.objects.map((obj) =>
-
- {JSON.stringify(obj.point.toArray())}
- {JSON.stringify(obj.object.userData)}
+ state.hitTest.hits.map((hit) =>
+
+ {JSON.stringify(hit.point.toArray())}
+ {JSON.stringify(hit.object.userData)}
)
}
diff --git a/client/src/components/ThreeVIew.tsx b/client/src/components/ThreeVIew.tsx
index c1bc179..ad9b217 100644
--- a/client/src/components/ThreeVIew.tsx
+++ b/client/src/components/ThreeVIew.tsx
@@ -2,9 +2,9 @@ import { useEffect, useRef } from "react";
import * as THREE from 'three';
import { useInteraction, type InteractionMouseEventArgs } from "../helpers/hooks/useInteration";
import { db } from "../backend/db";
-import { HitTestFactory, type HitTest } from "../helpers/hitTest";
import { model } from "../model/model";
import { SceneHelper } from "../helpers/sceneHelper";
+import type { HitResults } from "../helpers/circularFrustumIntersect";
export type ThreeViewEventArgs = {
camera: THREE.Camera,
@@ -17,7 +17,7 @@ export type ThreeViewTickEventArgs = ThreeViewEventArgs & {
}
export type ThreeViewMouseEventArgs = ThreeViewEventArgs & {
- hitTest: HitTest,
+ hitResults: HitResults,
}
export type ThreeViewProps = {
@@ -102,38 +102,27 @@ export const ThreeView = function (props: ThreeViewProps) {
window.addEventListener("resize", handleWindowResize);
handleHover = (e: InteractionMouseEventArgs) => {
-
- const ht = props.sceneHelper.hitTest(
+ const hitResults = props.sceneHelper.hitTest(
e.position,
e.screenSize,
);
- console.log(JSON.stringify(ht.map((h) => h.object.userData)));
-
- const hitTest = HitTestFactory.hitTest(
- props.sceneHelper,
- new THREE.Vector2(e.position.x, e.position.y),
- camera,
- { tolerancePixels: 3, cameraPixelSize: e.pixelSize }
- );
props.onMouseMove?.({
camera,
scene,
- hitTest,
+ hitResults,
});
};
handleClick = (e: InteractionMouseEventArgs) => {
- const hitTest = HitTestFactory.hitTest(
- props.sceneHelper,
- new THREE.Vector2(e.position.x, e.position.y),
- camera,
- { tolerancePixels: 3, cameraPixelSize: e.pixelSize }
+ const hitResults = props.sceneHelper.hitTest(
+ e.position,
+ e.screenSize,
);
props.onClick?.({
camera,
scene,
- hitTest,
- })
+ hitResults,
+ });
};
// --- Animation loop ---
diff --git a/client/src/components/Viewport.tsx b/client/src/components/Viewport.tsx
index f35f356..87cc596 100644
--- a/client/src/components/Viewport.tsx
+++ b/client/src/components/Viewport.tsx
@@ -7,12 +7,12 @@ export const Viewport = function () {
const sceneHelper = useSceneHelper();
function handleMouseMove(e: ThreeViewMouseEventArgs) {
- state.setHitTest(e.hitTest);
+ state.setHitTest(e.hitResults);
sceneHelper.clear();
- if (e.hitTest.objects.length) {
- e.hitTest.objects.forEach((obj) => {
- sceneHelper.showPoint(obj.object.uuid, obj.point);
+ if (e.hitResults.hits.length) {
+ e.hitResults.hits.forEach((hit) => {
+ sceneHelper.showPoint(hit.object.uuid, hit.point);
})
// console.log(e.position);
// console.log(e.hitTest.objects.map((o) => o));
@@ -20,7 +20,7 @@ export const Viewport = function () {
}
// raycaster.setFromCamera(new THREE.Vector2(e.x, e.y), camera);
// const hits = raycaster.intersectObjects(sync.meshes);
- const hoveredFaceIds = e.hitTest.objects.map(hit => hit.object.userData.faceId);
+ const hoveredFaceIds = e.hitResults.hits.map((hit) => hit.object.userData.faceId);
// if (hoveredFaceIds.length)
// console.log(hoveredFaceIds);
diff --git a/client/src/helpers/circularFrustumIntersect.ts b/client/src/helpers/circularFrustumIntersect.ts
index 9d1134f..94a3f47 100644
--- a/client/src/helpers/circularFrustumIntersect.ts
+++ b/client/src/helpers/circularFrustumIntersect.ts
@@ -2,7 +2,11 @@ import * as THREE from 'three';
import { CONTAINED, ExtendedTriangle, INTERSECTED, NOT_INTERSECTED } from 'three-mesh-bvh';
import { CircularFrustum } from './circularFrustum';
-export type FrustumHitResult = {
+export type HitResults = {
+ hits: HitResult[];
+}
+
+export type HitResult = {
object: THREE.Object3D;
point: THREE.Vector3; // world-space closest hit point
depth: number; // depth along frustum axis
@@ -119,7 +123,7 @@ export class CircularFrustumIntersection {
public intersectMesh(
mesh: THREE.Mesh,
findAll: boolean,
- ): FrustumHitResult[] {
+ ): HitResult[] {
const geometry = mesh.geometry;
if (!geometry)
return [];
@@ -136,7 +140,7 @@ export class CircularFrustumIntersection {
if (this.insersectsSphere(boundingSphere) === 'NOT_INTERSECTED')
return [];
- const results: FrustumHitResult[] = [];
+ const results: HitResult[] = [];
if (!geometry.boundsTree)
geometry.computeBoundsTree();
@@ -240,8 +244,8 @@ export class CircularFrustumIntersection {
public intersectObject(
obj: THREE.Object3D,
options: CircularFrustumIntersectionOptions = {},
- ): FrustumHitResult[] {
- const results: FrustumHitResult[] = [];
+ ): HitResult[] {
+ const results: HitResult[] = [];
obj.traverseVisible((object) => {
if (options.filter && !options.filter(object))
diff --git a/client/src/helpers/hitTest.ts b/client/src/helpers/hitTest.ts
deleted file mode 100644
index c72b72b..0000000
--- a/client/src/helpers/hitTest.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import * as THREE from 'three';
-import type { SceneHelper } from './sceneHelper';
-import './bvh';
-
-export type HitTest = {
- objects: THREE.Intersection[];
-}
-
-export type HitTestRaycasterOptions = {
- cameraPixelSize: THREE.Vector2Like;
- tolerancePixels: number;
-}
-
-export type HitTestOptions = HitTestRaycasterOptions & {
-}
-
-export class HitTestFactory {
-
- private static raycasters: [THREE.Vector2, THREE.Raycaster][] = Array(9).fill(0).map(() => [new THREE.Vector2(), new THREE.Raycaster()]);
-
- private static setupRaycasters(cursor: THREE.Vector2, camera: THREE.PerspectiveCamera, options: HitTestRaycasterOptions) {
-
- this.raycasters[0][0].copy(cursor);
- this.raycasters[0][1].setFromCamera(cursor, camera);
-
- const count = HitTestFactory.raycasters.length - 1;
- const step = Math.PI * 2 / count;
-
- for (let angle = 0, idx = 0; idx < count; angle += step, idx++) {
- const pos = {
- x: Math.cos(angle) * options.tolerancePixels * options.cameraPixelSize.x,
- y: Math.sin(angle) * options.tolerancePixels * options.cameraPixelSize.y,
- };
- const v = HitTestFactory.raycasters[idx + 1][0];
- v.copy(cursor).add(pos);
- HitTestFactory.raycasters[idx + 1][1].setFromCamera(v, camera);
- }
- }
-
- public static getRaycasterPosition(index: number): THREE.Vector2 {
- return HitTestFactory.raycasters[index][0];
- }
-
- public static get raycasterCount(): number {
- return HitTestFactory.raycasters.length;
- }
-
- public static hitTest(scene: SceneHelper, cursor: THREE.Vector2, camera: THREE.PerspectiveCamera, options: HitTestOptions): HitTest {
-
- HitTestFactory.setupRaycasters(cursor, camera, options);
-
- const objects: THREE.Object3D[] = scene.objects;
-
- const hitTest: Record> = {};
-
- HitTestFactory.raycasters.forEach((raycaster) => {
- const hits = raycaster[1].intersectObjects(objects);
- for (const hit of hits) {
- hitTest[hit.object.uuid] = hit;
- }
- });
-
- return {
- objects: Object.values(hitTest),
- }
- }
-}
diff --git a/client/src/helpers/sceneHelper.ts b/client/src/helpers/sceneHelper.ts
index 361b311..ca1fcb7 100644
--- a/client/src/helpers/sceneHelper.ts
+++ b/client/src/helpers/sceneHelper.ts
@@ -2,7 +2,7 @@ import type { ColorRepresentation, Object3D, Object3DEventMap, OrthographicCamer
import { SceneSync } from "../layers/sceneSync";
import { GeometryCache } from "../layers/geometryCache";
import type { Id } from "../types";
-import { CircularFrustumIntersection, type FrustumHitResult } from "./circularFrustumIntersect";
+import { CircularFrustumIntersection, type HitResult, type HitResults } from "./circularFrustumIntersect";
import { CircularFrustum } from "./circularFrustum";
import './bvh';
import { VolatileGeometryHelper, type VolatileGeometryOptions } from "./volatileGeometryHelper";
@@ -30,7 +30,7 @@ export class SceneHelper {
public buildMouseFrustum(
mouseNormalized: Vector2Like,
screenSize: Vector2Like,
- radius: number = 15,
+ radius: number = 5,
): void {
if (!this.camera)
throw new Error('Camera is not initialized');
@@ -46,13 +46,16 @@ export class SceneHelper {
public hitTest(
mouseNormalized: Vector2Like,
screenSize: Vector2Like,
- ): FrustumHitResult[] {
+ ): HitResults {
this.buildMouseFrustum(mouseNormalized, screenSize);
- const result: FrustumHitResult[] = [];
+ const hits: HitResult[] = [];
for (const object of this.objects)
- result.push(...this.mouseFrustum.intersectObject(object));
- return result;
+ hits.push(...this.mouseFrustum.intersectObject(object));
+
+ return {
+ hits,
+ };
}
public setSelection(faceIds: Id[]) {
diff --git a/client/src/state/root.ts b/client/src/state/root.ts
index cc8697d..1abe70a 100644
--- a/client/src/state/root.ts
+++ b/client/src/state/root.ts
@@ -1,10 +1,10 @@
import { makeAutoObservable } from "mobx";
import type { Id } from "../types";
-import type { HitTest } from "../helpers/hitTest";
+import type { HitResults } from "../helpers/circularFrustumIntersect";
export class Root {
public selectedPrimitiveIds: Id[] = [];
- public hitTest: HitTest = { objects: [] };
+ public hitTest: HitResults = { hits: [] };
constructor() {
makeAutoObservable(this);
@@ -14,7 +14,7 @@ export class Root {
this.selectedPrimitiveIds = value;
}
- public setHitTest(value: HitTest) {
+ public setHitTest(value: HitResults) {
this.hitTest = value;
}
}