XRPlanes.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import {
  2. BoxGeometry,
  3. Matrix4,
  4. Mesh,
  5. MeshBasicMaterial,
  6. Object3D
  7. } from 'three';
  8. /**
  9. * A utility class for the WebXR Plane Detection Module. If planes
  10. * are detected by WebXR, this class will automatically add them
  11. * as thin box meshes to the scene when below code snippet is used.
  12. *
  13. * ```js
  14. * const planes = new XRPlanes( renderer );
  15. * scene.add( planes );
  16. * ```
  17. *
  18. * @augments Object3D
  19. * @three_import import { XRPlanes } from 'three/addons/webxr/XRPlanes.js';
  20. */
  21. class XRPlanes extends Object3D {
  22. /**
  23. * Constructs a new XR plane container.
  24. *
  25. * @param {WebGLRenderer|WebGPURenderer} renderer - The renderer.
  26. */
  27. constructor( renderer ) {
  28. super();
  29. const matrix = new Matrix4();
  30. const currentPlanes = new Map();
  31. const xr = renderer.xr;
  32. xr.addEventListener( 'planesdetected', event => {
  33. const frame = event.data;
  34. const planes = frame.detectedPlanes;
  35. const referenceSpace = xr.getReferenceSpace();
  36. let planeschanged = false;
  37. for ( const [ plane, mesh ] of currentPlanes ) {
  38. if ( planes.has( plane ) === false ) {
  39. mesh.geometry.dispose();
  40. mesh.material.dispose();
  41. this.remove( mesh );
  42. currentPlanes.delete( plane );
  43. planeschanged = true;
  44. }
  45. }
  46. for ( const plane of planes ) {
  47. if ( currentPlanes.has( plane ) === false ) {
  48. const pose = frame.getPose( plane.planeSpace, referenceSpace );
  49. matrix.fromArray( pose.transform.matrix );
  50. const polygon = plane.polygon;
  51. let minX = Number.MAX_SAFE_INTEGER;
  52. let maxX = Number.MIN_SAFE_INTEGER;
  53. let minZ = Number.MAX_SAFE_INTEGER;
  54. let maxZ = Number.MIN_SAFE_INTEGER;
  55. for ( const point of polygon ) {
  56. minX = Math.min( minX, point.x );
  57. maxX = Math.max( maxX, point.x );
  58. minZ = Math.min( minZ, point.z );
  59. maxZ = Math.max( maxZ, point.z );
  60. }
  61. const width = maxX - minX;
  62. const height = maxZ - minZ;
  63. const geometry = new BoxGeometry( width, 0.01, height );
  64. const material = new MeshBasicMaterial( { color: 0xffffff * Math.random() } );
  65. const mesh = new Mesh( geometry, material );
  66. mesh.position.setFromMatrixPosition( matrix );
  67. mesh.quaternion.setFromRotationMatrix( matrix );
  68. this.add( mesh );
  69. currentPlanes.set( plane, mesh );
  70. planeschanged = true;
  71. }
  72. }
  73. if ( planeschanged ) {
  74. this.dispatchEvent( { type: 'planeschanged' } );
  75. }
  76. } );
  77. }
  78. }
  79. export { XRPlanes };