UNPKG

@adhiban/three-mesh-ui

Version:

a library on top of three.js to help in creating 3D user interfaces, with minor changes ;)

227 lines (157 loc) 5.07 kB
/* Job: creating the VR controllers and their pointers */ import * as THREE from 'three'; import { XRControllerModelFactory } from 'three/examples/jsm/webxr/XRControllerModelFactory.js'; export default function VRControl( renderer ) { const controllers = []; const controllerGrips = []; const controllerModelFactory = new XRControllerModelFactory(); ////////////////// // Lines helpers ////////////////// const material = new THREE.MeshBasicMaterial( { color: 0xffffff, alphaMap: new THREE.CanvasTexture( generateRayTexture() ), transparent: true } ); const geometry = new THREE.BoxBufferGeometry( 0.004, 0.004, 0.35 ); geometry.translate( 0, 0, -0.15 ); const uvAttribute = geometry.attributes.uv; for ( let i = 0; i < uvAttribute.count; i++ ) { let u = uvAttribute.getX( i ); let v = uvAttribute.getY( i ); [ u, v ] = ( () => { switch ( i ) { case 0 : return [ 1, 1 ]; case 1 : return [ 0, 0 ]; case 2 : return [ 1, 1 ]; case 3 : return [ 0, 0 ]; case 4 : return [ 0, 0 ]; case 5 : return [ 1, 1 ]; case 6 : return [ 0, 0 ]; case 7 : return [ 1, 1 ]; case 8 : return [ 0, 0 ]; case 9 : return [ 0, 0 ]; case 10 : return [ 1, 1 ]; case 11 : return [ 1, 1 ]; case 12 : return [ 1, 1 ]; case 13 : return [ 1, 1 ]; case 14 : return [ 0, 0 ]; case 15 : return [ 0, 0 ]; default : return [ 0, 0 ]; } } )(); uvAttribute.setXY( i, u, v ); } const linesHelper = new THREE.Mesh( geometry, material ); linesHelper.renderOrder = Infinity; ///////////////// // Point helper ///////////////// const spriteMaterial = new THREE.SpriteMaterial( { map: new THREE.CanvasTexture( generatePointerTexture() ), sizeAttenuation: false, depthTest: false } ); const pointer = new THREE.Sprite( spriteMaterial ); pointer.scale.set( 0.015, 0.015, 1 ); pointer.renderOrder = Infinity; //////////////// // Controllers //////////////// const controller1 = renderer.xr.getController( 0 ); const controller2 = renderer.xr.getController( 1 ); controller1.name = 'controller-right'; controller2.name = 'controller-left'; const controllerGrip1 = renderer.xr.getControllerGrip( 0 ); const controllerGrip2 = renderer.xr.getControllerGrip( 1 ); if ( controller1 ) controllers.push( controller1 ); if ( controller2 ) controllers.push( controller2 ); if ( controllerGrip1 ) controllerGrips.push( controllerGrip1 ); if ( controllerGrip2 ) controllerGrips.push( controllerGrip2 ); controllers.forEach( ( controller ) => { const ray = linesHelper.clone(); const point = pointer.clone(); controller.add( ray, point ); controller.ray = ray; controller.point = point; } ); controllerGrips.forEach( ( controllerGrip ) => { controllerGrip.add( controllerModelFactory.createControllerModel( controllerGrip ) ); } ); ////////////// // Functions ////////////// const dummyMatrix = new THREE.Matrix4(); // Set the passed ray to match the given controller pointing direction function setFromController( controllerID, ray ) { const controller = controllers[ controllerID ]; // Position the intersection ray dummyMatrix.identity().extractRotation( controller.matrixWorld ); ray.origin.setFromMatrixPosition( controller.matrixWorld ); ray.direction.set( 0, 0, -1 ).applyMatrix4( dummyMatrix ); } // Position the chosen controller's pointer at the given point in space. // Should be called after raycaster.intersectObject() found an intersection point. function setPointerAt( controllerID, vec ) { const controller = controllers[ controllerID ]; const localVec = controller.worldToLocal( vec ); controller.point.position.copy( localVec ); controller.point.visible = true; } // return { controllers, controllerGrips, setFromController, setPointerAt }; } ////////////////////////////// // CANVAS TEXTURE GENERATION ////////////////////////////// // Generate the texture needed to make the intersection ray fade away function generateRayTexture() { const canvas = document.createElement( 'canvas' ); canvas.width = 64; canvas.height = 64; const ctx = canvas.getContext( '2d' ); const gradient = ctx.createLinearGradient( 0, 0, 64, 0 ); gradient.addColorStop( 0, 'black' ); gradient.addColorStop( 1, 'white' ); ctx.fillStyle = gradient; ctx.fillRect( 0, 0, 64, 64 ); return canvas; } // Generate the texture of the point helper sprite function generatePointerTexture() { const canvas = document.createElement( 'canvas' ); canvas.width = 64; canvas.height = 64; const ctx = canvas.getContext( '2d' ); ctx.beginPath(); ctx.arc( 32, 32, 29, 0, 2 * Math.PI ); ctx.lineWidth = 5; ctx.stroke(); ctx.fillStyle = 'white'; ctx.fill(); return canvas; }