Skip to content

Commit

Permalink
adding ar plane detection events
Browse files Browse the repository at this point in the history
  • Loading branch information
richardanaya committed Oct 30, 2022
1 parent 4cd8eef commit dca2c33
Show file tree
Hide file tree
Showing 4 changed files with 236 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@
"webxr_ar_hittest",
"webxr_ar_lighting",
"webxr_ar_paint",
"webxr_ar_plane_detection",
"webxr_vr_ballshooter",
"webxr_vr_cubes",
"webxr_vr_dragging",
Expand Down
Binary file added examples/screenshots/webxr_ar_plane_detection.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
167 changes: 167 additions & 0 deletions examples/webxr_ar_plane_detection.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js ar - plane detection</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>

<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> ar - plane detection<br/>(Chrome Android 81+)
</div>

<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>

<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/"
}
}
</script>

<script type="module">

import * as THREE from 'three';
import { ARButton } from 'three/addons/webxr/ARButton.js';

let camera, scene, renderer;
let controller;

init();
animate();

const planesAdded = new Set();

function init() {

const container = document.createElement( 'div' );
document.body.appendChild( container );

scene = new THREE.Scene();

camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 20 );

const light = new THREE.HemisphereLight( 0xffffff, 0xbbbbff, 1 );
light.position.set( 0.5, 1, 0.25 );
scene.add( light );

//

renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.xr.enabled = true;
container.appendChild( renderer.domElement );

//

document.body.appendChild( ARButton.createButton( renderer, {
requiredFeatures: ['plane-detection']
} ) );

//

window.addEventListener( 'resize', onWindowResize );

renderer.xr.addEventListener( 'sessionstart', function () {

camera.position.set( 0, 0, 0 );

} );

renderer.xr.addEventListener( 'planeadded', function (e) {

console.log( "plane added", e.data )

} );

renderer.xr.addEventListener( 'planeremoved', function (e) {

console.log( "plane removed", e.data )

} );

renderer.xr.addEventListener( 'planechanged', function (e) {

console.log( "plane changed", e.data)

} );

renderer.xr.addEventListener( 'planesdetected', function (e) {

const detectedPlanes = e.data;
const referenceSpace = renderer.xr.getReferenceSpace();

console.log( `Detected ${detectedPlanes.size} planes` );

detectedPlanes.forEach( plane => {

if ( planesAdded.has( plane ) ) return;

planesAdded.add( plane );
const frame = renderer.xr.getFrame();
const planePose = frame.getPose( plane.planeSpace, referenceSpace );
const planeGeometry = new THREE.BufferGeometry();
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;

polygon.forEach( point => {

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 boxMesh = new THREE.Mesh(
new THREE.BoxGeometry( width, 0.01, height ),
new THREE.MeshBasicMaterial( { color: 0xffffff * Math.random() } )
);
boxMesh.matrixAutoUpdate = false;
boxMesh.matrix.fromArray( planePose.transform.matrix );
scene.add( boxMesh );

} );
} );
}

function onWindowResize() {

camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

renderer.setSize( window.innerWidth, window.innerHeight );

}

//

function animate() {

renderer.setAnimationLoop( render );

}

function render() {

renderer.render( scene, camera );

}

</script>
</body>
</html>
68 changes: 68 additions & 0 deletions src/renderers/webxr/WebXRManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class WebXRManager extends EventDispatcher {
const controllers = [];
const controllerInputSources = [];

const planes = new Set();
const planesLastChangedTimes = new Map();

//

const cameraL = new PerspectiveCamera();
Expand Down Expand Up @@ -600,6 +603,12 @@ class WebXRManager extends EventDispatcher {

};

this.getPlanes = function () {

return planes;

};

// Animation Loop

let onAnimationFrameCallback = null;
Expand Down Expand Up @@ -708,6 +717,65 @@ class WebXRManager extends EventDispatcher {

if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );

if ( frame.detectedPlanes ) {

scope.dispatchEvent( { type: 'planesdetected', data: frame.detectedPlanes } );

let planesToRemove = null;

for ( const plane of planes ) {

if ( ! frame.detectedPlanes.has( plane ) ) {

if ( planesToRemove === null ) {

planesToRemove = [];

}

planesToRemove.push( plane );

}

}

if ( planesToRemove !== null ) {

for ( const plane of planesToRemove ) {

planes.delete( plane );
planesLastChangedTimes.delete( plane );
scope.dispatchEvent( { type: 'planeremoved', data: plane } );

}

}

for ( const plane of frame.detectedPlanes ) {

if ( ! planes.has( plane ) ) {

planes.add( plane );
planesLastChangedTimes.set( plane, frame.lastChangedTime );
scope.dispatchEvent( { type: 'planeadded', data: plane } );

} else {

const lastKnownTime = planesLastChangedTimes.get( plane );

if ( plane.lastChangedTime > lastKnownTime ) {

planesLastChangedTimes.set( plane, plane.lastChangedTime );
scope.dispatchEvent( { type: 'planechanged', data: plane } );

}

}

}

}

xrFrame = null;

}
Expand Down

0 comments on commit dca2c33

Please sign in to comment.