Skip to content

Commit d682279

Browse files
committed
improve intersection speed
1 parent 5c132e8 commit d682279

File tree

10 files changed

+155
-171
lines changed

10 files changed

+155
-171
lines changed

examples/react-three-xr/app.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ export function App() {
2020
<ambientLight />
2121
<XROrigin position={position} />
2222
<Cube />
23-
{/*<Smoke count={100} maxSize={0.3} minSize={0.1} spawnRate={10} speed={0.1} />
23+
<Smoke count={100} maxSize={0.3} minSize={0.1} spawnRate={10} speed={0.1} />
2424
<TeleportTarget onTeleport={setPosition}>
2525
<mesh scale={[10, 1, 10]} position={[0, -0.5, 0]}>
2626
<boxGeometry />
2727
<meshBasicMaterial color="green" />
2828
</mesh>
29-
</TeleportTarget>*/}
29+
</TeleportTarget>
3030
</XR>
3131
</Canvas>
3232
</>

examples/vanilla/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,21 @@ const canvas = document.getElementById('root') as HTMLCanvasElement
3434
const renderer = new WebGLRenderer({ antialias: true, canvas, alpha: true })
3535
renderer.xr.enabled = true
3636

37-
const teleportTarget = new Mesh(new BoxGeometry(), new MeshBasicMaterial({ color: 'yellow' }))
37+
const teleportTarget = new Mesh(new BoxGeometry(), new MeshBasicMaterial({ color: 'black' }))
3838
teleportTarget.position.y = -0.5
3939
teleportTarget.scale.set(100, 1, 100)
4040
makeTeleportTarget(teleportTarget, camera, (point) => origin.position.copy(point))
4141
scene.add(teleportTarget)
4242

43-
const store = createXRStore(canvas, scene, camera, renderer.xr, {
43+
const store = createXRStore(canvas, scene, () => camera, renderer.xr, {
4444
hand: {
4545
model: { colorWrite: false, renderOrder: -1 },
4646
grabPointer: false,
4747
teleportPointer: true,
4848
},
4949
controller: {
5050
model: { colorWrite: false, renderOrder: -1 },
51+
teleportPointer: true,
5152
},
5253
})
5354
document.getElementById('enter-ar')?.addEventListener('click', () => store.enterAR())

packages/pointer-events/bench/pointer.bench.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import { bench, describe } from 'vitest'
22
import { createRayPointer } from '../src/pointer/index.js'
3-
import { BoxGeometry, Mesh, Object3D, Raycaster, Scene } from 'three'
3+
import { BoxGeometry, Mesh, Object3D, PerspectiveCamera, Raycaster, Scene } from 'three'
44
import { CombinedPointer } from '../src/combine.js'
55

6+
const camera = new PerspectiveCamera()
67
const combinedPointer = new CombinedPointer(true)
78
const leftPointer = new CombinedPointer(false)
89
combinedPointer.register(leftPointer)
910
new Array(5).fill(undefined).forEach(() =>
1011
leftPointer.register(
1112
createRayPointer(
13+
() => camera,
1214
{
1315
current: new Object3D(),
1416
},
@@ -21,6 +23,7 @@ combinedPointer.register(rightPointer)
2123
new Array(5).fill(undefined).forEach(() =>
2224
rightPointer.register(
2325
createRayPointer(
26+
() => camera,
2427
{
2528
current: new Object3D(),
2629
},
@@ -30,6 +33,7 @@ new Array(5).fill(undefined).forEach(() =>
3033
)
3134

3235
const singlePointer = createRayPointer(
36+
() => camera,
3337
{
3438
current: new Object3D(),
3539
},

packages/pointer-events/src/intersections/intersector.ts

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,10 @@ export function getVoidObject(scene: Object3D): Object3D {
2121
return entry
2222
}
2323

24-
export abstract class Intersector {
25-
//state of the current intersection
26-
protected intersection: ThreeIntersection | undefined
27-
protected pointerEventsOrder: number | undefined
28-
29-
public startIntersection(nativeEvent: unknown): void {
30-
this.intersection = undefined
31-
this.pointerEventsOrder = undefined
32-
this.prepareIntersection(nativeEvent)
33-
}
34-
35-
public abstract intersectPointerCapture(pointerCapture: PointerCapture, nativeEvent: unknown): Intersection
36-
37-
public abstract isReady(): boolean
38-
39-
protected abstract prepareIntersection(nativeEvent: unknown): void
40-
41-
public abstract executeIntersection(scene: Object3D, objectPointerEventsOrder: number): void
42-
43-
public abstract finalizeIntersection(scene: Object3D): Intersection
24+
export interface Intersector {
25+
intersectPointerCapture(pointerCapture: PointerCapture, nativeEvent: unknown): Intersection
26+
isReady(): boolean
27+
startIntersection(nativeEvent: unknown): void
28+
executeIntersection(scene: Object3D, objectPointerEventsOrder: number): void
29+
finalizeIntersection(scene: Object3D): Intersection
4430
}

packages/pointer-events/src/intersections/lines.ts

Lines changed: 40 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,37 @@ import {
99
Intersection as ThreeIntersection,
1010
Object3D,
1111
} from 'three'
12-
import { computeIntersectionWorldPlane, getDominantIntersectionIndex, voidObjectIntersectionFromRay } from './utils.js'
12+
import {
13+
computeIntersectionWorldPlane,
14+
getDominantIntersectionIndex,
15+
pushTimes,
16+
voidObjectIntersectionFromRay,
17+
} from './utils.js'
1318
import type { PointerCapture } from '../pointer.js'
1419
import { Intersector } from './intersector.js'
1520
import { Intersection, IntersectionOptions } from '../index.js'
1621
import { updateAndCheckWorldTransformation } from '../utils.js'
1722

1823
const invertedMatrixHelper = new Matrix4()
19-
const intersectsHelper: Array<ThreeIntersection & { details: { distanceOnLine: number; lineIndex: number } }> = []
2024
const lineHelper = new Line3()
2125
const planeHelper = new Plane()
2226
const rayHelper = new Ray()
2327
const defaultLinePoints = [new Vector3(0, 0, 0), new Vector3(0, 0, 1)]
2428

25-
export class LinesIntersector extends Intersector {
29+
export class LinesIntersector implements Intersector {
2630
private raycasters: Array<Raycaster> = []
2731
private fromMatrixWorld = new Matrix4()
2832

29-
//state
30-
private intersectionLineIndex: number = 0
31-
private intersectionDistanceOnLine: number = 0
32-
3333
private ready?: boolean
3434

35+
private intersects: Array<ThreeIntersection> = []
36+
private readonly pointerEventsOrders: Array<number | undefined> = []
37+
private readonly raycasterIndices: Array<number> = []
38+
3539
constructor(
3640
private readonly space: { current?: Object3D | null },
3741
private readonly options: IntersectionOptions & { linePoints?: Array<Vector3>; minDistance?: number },
38-
) {
39-
super()
40-
}
42+
) {}
4143

4244
public isReady(): boolean {
4345
return this.ready ?? this.prepareTransformation()
@@ -81,7 +83,7 @@ export class LinesIntersector extends Intersector {
8183
}
8284
}
8385

84-
protected prepareIntersection(): void {
86+
startIntersection(): void {
8587
if (!this.prepareTransformation()) {
8688
return
8789
}
@@ -110,37 +112,29 @@ export class LinesIntersector extends Intersector {
110112
if (!this.isReady()) {
111113
return
112114
}
113-
let lineLengthSum = 0
115+
const startOuter = this.intersects.length
114116
const length = this.raycasters.length
115-
//TODO: optimize - we only need to intersect with raycasters before or equal to the raycaster that did the current intersection
116117
for (let i = 0; i < length; i++) {
117118
const raycaster = this.raycasters[i]
118-
object.raycast(raycaster, intersectsHelper)
119-
for (const intersection of intersectsHelper) {
120-
intersection.distance += lineLengthSum
121-
}
122-
const index = getDominantIntersectionIndex(
123-
this.intersection,
124-
this.pointerEventsOrder,
125-
intersectsHelper,
126-
objectPointerEventsOrder,
127-
this.options,
128-
)
129-
if (index != null) {
130-
this.intersection = intersectsHelper[index]
131-
this.intersectionLineIndex = i
132-
this.intersectionDistanceOnLine = this.intersection.distance - raycaster.far
133-
this.pointerEventsOrder = objectPointerEventsOrder
134-
}
135-
intersectsHelper.length = 0
136-
lineLengthSum += raycaster.far
119+
const startInner = this.intersects.length
120+
object.raycast(raycaster, this.intersects)
121+
pushTimes(this.raycasterIndices, i, this.intersects.length - startInner)
137122
}
123+
pushTimes(this.pointerEventsOrders, objectPointerEventsOrder, this.intersects.length - startOuter)
138124
}
139125

140126
public finalizeIntersection(scene: Object3D): Intersection {
141127
const pointerPosition = new Vector3().setFromMatrixPosition(this.fromMatrixWorld)
142128
const pointerQuaternion = new Quaternion().setFromRotationMatrix(this.fromMatrixWorld)
143-
if (this.intersection == null) {
129+
130+
const index = getDominantIntersectionIndex(this.intersects, this.pointerEventsOrders, this.options)
131+
const intersection = index == null ? undefined : this.intersects[index]
132+
const raycasterIndex = index == null ? undefined : this.raycasterIndices[index]
133+
this.intersects.length = 0
134+
this.raycasterIndices.length = 0
135+
this.pointerEventsOrders.length = 0
136+
137+
if (intersection == null || raycasterIndex == null) {
144138
const lastRaycasterIndex = this.raycasters.length - 1
145139
const prevDistance = this.raycasters.reduce(
146140
(prev, caster, i) => (i === lastRaycasterIndex ? prev : prev + caster.far),
@@ -160,19 +154,26 @@ export class LinesIntersector extends Intersector {
160154
prevDistance,
161155
)
162156
}
157+
158+
let distance = intersection.distance
159+
for (let i = 0; i < raycasterIndex; i++) {
160+
distance += this.raycasters[i].far
161+
}
162+
163163
//TODO: consider maxLength
164-
return Object.assign(this.intersection, {
164+
return Object.assign(intersection, {
165165
details: {
166-
lineIndex: this.intersectionLineIndex,
167-
distanceOnLine: this.intersectionDistanceOnLine,
166+
lineIndex: raycasterIndex,
167+
distanceOnLine: intersection.distance,
168168
type: 'lines' as const,
169169
},
170+
distance,
170171
pointerPosition,
171172
pointerQuaternion,
172-
pointOnFace: this.intersection.point,
173-
localPoint: this.intersection.point
173+
pointOnFace: intersection.point,
174+
localPoint: intersection.point
174175
.clone()
175-
.applyMatrix4(invertedMatrixHelper.copy(this.intersection.object.matrixWorld).invert()),
176+
.applyMatrix4(invertedMatrixHelper.copy(intersection.object.matrixWorld).invert()),
176177
})
177178
}
178179
}

0 commit comments

Comments
 (0)