From d051272b0d6fc1cd4593a7b8f3a985534d0d4d97 Mon Sep 17 00:00:00 2001 From: Cody Bennett <23324155+CodyJasonBennett@users.noreply.github.com> Date: Sun, 4 Jun 2023 17:40:44 -0500 Subject: [PATCH 1/2] feat: XRPlanes --- src/webxr/XRPlanes.ts | 64 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/webxr/XRPlanes.ts diff --git a/src/webxr/XRPlanes.ts b/src/webxr/XRPlanes.ts new file mode 100644 index 00000000..d74f7d92 --- /dev/null +++ b/src/webxr/XRPlanes.ts @@ -0,0 +1,64 @@ +import { BoxGeometry, Matrix4, WebGLRenderer, Mesh, MeshBasicMaterial, Object3D } from 'three' + +const geometry = /* @__PURE__ */ new BoxGeometry() +const matrix = /* @__PURE__ */ new Matrix4() + +class XRPlanes extends Object3D { + constructor(renderer: WebGLRenderer) { + super() + + const currentPlanes = new Map() + + renderer.xr.addEventListener('planesdetected', (event) => { + const frame = event.data + const planes = frame.detectedPlanes + + const referenceSpace = renderer.xr.getReferenceSpace() + + for (const [plane, mesh] of currentPlanes) { + if (planes.has(plane) === false) { + mesh.material.dispose() + this.remove(mesh) + + currentPlanes.delete(plane) + } + } + + for (const plane of planes) { + if (currentPlanes.has(plane) === false) { + const pose = frame.getPose(plane.planeSpace, referenceSpace) + matrix.fromArray(pose.transform.matrix) + + const polygon = plane.polygon + + let minX = Number.MAX_SAFE_INTEGER + let maxX = Number.MIN_SAFE_INTEGER + let minZ = Number.MAX_SAFE_INTEGER + let maxZ = Number.MIN_SAFE_INTEGER + + for (const point of polygon) { + minX = Math.min(minX, point.x) + maxX = Math.max(maxX, point.x) + minZ = Math.min(minZ, point.z) + maxZ = Math.max(maxZ, point.z) + } + + const width = maxX - minX + const height = maxZ - minZ + + const material = new MeshBasicMaterial({ color: 0xffffff * Math.random() }) + + const mesh = new Mesh(geometry, material) + mesh.position.setFromMatrixPosition(matrix) + mesh.quaternion.setFromRotationMatrix(matrix) + mesh.scale.set(width, 0.01, height) + this.add(mesh) + + currentPlanes.set(plane, mesh) + } + } + }) + } +} + +export { XRPlanes } From 8388ce7882c323ebd79b3d38dc084783da070853 Mon Sep 17 00:00:00 2001 From: Cody Bennett <23324155+CodyJasonBennett@users.noreply.github.com> Date: Sun, 4 Jun 2023 18:24:13 -0500 Subject: [PATCH 2/2] fix: get planes working again --- src/index.ts | 1 + src/webxr/XRPlanes.ts | 97 ++++++++++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 37 deletions(-) diff --git a/src/index.ts b/src/index.ts index 60f76649..0d99ad99 100644 --- a/src/index.ts +++ b/src/index.ts @@ -112,6 +112,7 @@ export * from './webxr/XREstimatedLight' export * from './webxr/XRHandMeshModel' export * from './webxr/XRHandModelFactory' export * from './webxr/XRHandPrimitiveModel' +export * from './webxr/XRPlanes' export * from './geometries/ParametricGeometries' export * from './geometries/ParametricGeometry' export * from './geometries/ConvexGeometry' diff --git a/src/webxr/XRPlanes.ts b/src/webxr/XRPlanes.ts index d74f7d92..ce5dfc22 100644 --- a/src/webxr/XRPlanes.ts +++ b/src/webxr/XRPlanes.ts @@ -4,60 +4,83 @@ const geometry = /* @__PURE__ */ new BoxGeometry() const matrix = /* @__PURE__ */ new Matrix4() class XRPlanes extends Object3D { + public renderer: WebGLRenderer + readonly currentPlanes = new Map>() + constructor(renderer: WebGLRenderer) { super() - const currentPlanes = new Map() + this.renderer = renderer + this._onPlanesUpdate = this._onPlanesUpdate.bind(this) + this.renderer.xr.addEventListener('planesdetected', this._onPlanesUpdate) + } - renderer.xr.addEventListener('planesdetected', (event) => { - const frame = event.data - const planes = frame.detectedPlanes + private _onPlanesUpdate() { + // @ts-ignore https://github.com/mrdoob/three.js/pull/22260 + const frame = this.renderer.xr.getFrame() as XRFrame - const referenceSpace = renderer.xr.getReferenceSpace() + // Event signature changed from XRPlaneSet => XRFRame + // https://github.com/mrdoob/three.js/pull/24855 + // https://github.com/mrdoob/three.js/pull/26098 + this.update(frame) + } - for (const [plane, mesh] of currentPlanes) { - if (planes.has(plane) === false) { - mesh.material.dispose() - this.remove(mesh) + update(frame: XRFrame): void { + const planes = (frame as any).detectedPlanes as XRPlaneSet - currentPlanes.delete(plane) - } + for (const [plane, mesh] of this.currentPlanes) { + if (!planes.has(plane)) { + mesh.material.dispose() + this.remove(mesh) + this.currentPlanes.delete(plane) } + } - for (const plane of planes) { - if (currentPlanes.has(plane) === false) { - const pose = frame.getPose(plane.planeSpace, referenceSpace) - matrix.fromArray(pose.transform.matrix) + const referenceSpace = this.renderer.xr.getReferenceSpace() + for (const plane of planes) { + if (!this.currentPlanes.has(plane)) { + const pose = frame.getPose(plane.planeSpace, referenceSpace!)! - const polygon = plane.polygon + matrix.fromArray(pose.transform.matrix) - let minX = Number.MAX_SAFE_INTEGER - let maxX = Number.MIN_SAFE_INTEGER - let minZ = Number.MAX_SAFE_INTEGER - let maxZ = Number.MIN_SAFE_INTEGER + let minX = Number.MAX_SAFE_INTEGER + let maxX = Number.MIN_SAFE_INTEGER + let minZ = Number.MAX_SAFE_INTEGER + let maxZ = Number.MIN_SAFE_INTEGER - for (const point of polygon) { - minX = Math.min(minX, point.x) - maxX = Math.max(maxX, point.x) - minZ = Math.min(minZ, point.z) - maxZ = Math.max(maxZ, point.z) - } + for (const point of plane.polygon) { + minX = Math.min(minX, point.x) + maxX = Math.max(maxX, point.x) + minZ = Math.min(minZ, point.z) + maxZ = Math.max(maxZ, point.z) + } - const width = maxX - minX - const height = maxZ - minZ + const width = maxX - minX + const height = maxZ - minZ - const material = new MeshBasicMaterial({ color: 0xffffff * Math.random() }) + const material = new MeshBasicMaterial({ color: 0xffffff * Math.random() }) - const mesh = new Mesh(geometry, material) - mesh.position.setFromMatrixPosition(matrix) - mesh.quaternion.setFromRotationMatrix(matrix) - mesh.scale.set(width, 0.01, height) - this.add(mesh) + const mesh = new Mesh(geometry, material) + mesh.position.setFromMatrixPosition(matrix) + mesh.quaternion.setFromRotationMatrix(matrix) + mesh.scale.set(width, 0.01, height) - currentPlanes.set(plane, mesh) - } + this.add(mesh) + this.currentPlanes.set(plane, mesh) } - }) + } + } + + dispose(): void { + geometry.dispose() + + for (const [plane, mesh] of this.currentPlanes) { + mesh.material.dispose() + this.remove(mesh) + this.currentPlanes.delete(plane) + } + + this.renderer.xr.removeEventListener('planesdetected', this._onPlanesUpdate) } }