UNPKG

readyaim

Version:

readyaim provides an aiming mechanism using a THREE.js camera

402 lines (338 loc) 10.3 kB
// Filename: readyaim_demo.js // Timestamp: 2017.11.11-23:10:02 (last modified) // Author(s): bumblehead <chris@bumblehead.com> const THREE = require('three'), touchboom = require('touchboom'), readyaim = require('./readyaim'); function setup (fn, cfg) { const loader = new THREE.FontLoader(); loader.load(cfg.fontpath, font => { cfg.font = font; fn(cfg); }); } function getrootelem () { return document.body; } function getwindowwh () { return [ Math.floor(window.innerWidth), Math.floor(window.innerHeight) ]; } // function getwindowhalfwh () { // return getwindowwh().map(wh => wh / 2); // } function degreetoradian (d) { return d * (Math.PI / 180); } function pixeltodegree (p, pw) { return p * pw; } function pixelweightarea (wh) { return 180 / Math.max(wh[0], wh[1]); } function pixelweight (elem) { return pixelweightarea( elem === window ? [ elem.innerWidth, elem.innerHeight ] : [ elem.clientWidth, elem.clientHeight ]); } function getcanvaselem (cfg) { let canvaselem = document.createElement('canvas'), [ w, h ] = cfg.wh; canvaselem.style.width = `${w}px`; canvaselem.style.height = `${h}px`; canvaselem.width = w; canvaselem.height = h; if (cfg.bg) { canvaselem.style.backgroundColor = cfg.bg; } if (cfg.className) { canvaselem.className = cfg.className; } return canvaselem; } function appendchild (parent, child) { parent.appendChild(child); return child; } function getglrenderer (canvaselem) { return new THREE.WebGLRenderer({ canvas : canvaselem, alpha : true, antialias : true }); } function getskymesh (cfg) { return new THREE.Mesh( (new THREE.SphereGeometry(600, 30, 30)) .applyMatrix(new THREE.Matrix4().makeScale(-1, 1, 1)), new THREE.MeshBasicMaterial({ map : readyaim.three.getfilterimgtexture(THREE, cfg.bgskyimg), transparent : false, side : THREE.FrontSide, overdraw : true // wireframe : true, // color : cfg.bgskycolor })); } // function getTextSprite (cfg, text) { // return new text2d.SpriteText2D(String(text), { // //return new text2d.MeshText2D(String(text), { // align : text2d.textAlign.center, // font : '40px Arial', // fillStyle : cfg.bgtextcolor, // antialias : false // }); // } // function getTextSprite (text, font) { // return new THREE.Mesh( // new THREE.TextGeometry(String(text), { // size : 40, // height : 1, // weight : 'normal', // font, // style : 'normal', // bevelThickness : 2, // bevelSize : 1, // bevelSegments : 3, // bevelEnabled : true, // curveSegments : 12, // steps : 1 // }), // new THREE.MeshBasicMaterial({ // color : 0xffffff // }) // ); // } // function getNumRandomSprite ( cfg ) { // return getTextSprite(cfg, Math.floor(Math.random() * 10)); // } function getscene (cfg, canvaselem) { let wharr = [ canvaselem.offsetWidth, canvaselem.offsetHeight ], glscene = new THREE.Scene(), camera = new THREE.PerspectiveCamera(60, wharr[0] / wharr[1], 1, 10000), skymesh = getskymesh(cfg), glrenderer = getglrenderer(canvaselem), headgroup = new THREE.Object3D(), bodygroup = new THREE.Group(), scenegroup = new THREE.Group(); headgroup.add(camera); bodygroup.add(headgroup); scenegroup.add(bodygroup); scenegroup.rotation.y = -THREE.Math.degToRad(90); glscene.add(scenegroup); glscene.add(skymesh); camera.position.set(0, 0, -24); camera.lookAt(glscene.position); glscene.rotation.y += -Math.PI / 2; return { wharr, skymesh, headgroup, bodygroup, glrenderer, camera, glscene }; } function getfloormesh () { let geometry = new THREE.PlaneGeometry(1000, 1000, 1, 1), material = new THREE.MeshBasicMaterial({ color : 0x000000 }), floor = new THREE.Mesh(geometry, material); floor.material.side = THREE.DoubleSide; floor.rotation.x = 90 * (Math.PI / 180); // degree to radian; return floor; } function getpanelmesh (cfg) { return new THREE.Mesh( new THREE.CubeGeometry(10, 300, 100), new THREE.MeshPhongMaterial({ color : cfg.color, emissive : cfg.color }) ); } // function alongVertex (cfg, font, canvasscene, textSprite) { // (new THREE.Mesh( // new THREE.SphereGeometry(380, 20, 20))).geometry.vertices // .filter(({ x, y }) => ( // (x > 350 || x < -350) && // y < 60 && y > -60 // )) // .map(({ x, y, z }) => { // let sprite = getTextSprite('3', font); // // textSprite.position.set(x, y, z); // textSprite.lookAt(canvasscene.glscene.position); // // canvasscene.glscene.add(sprite); // }); // } // function countadd (value, font, scene) { // let textSprite = getTextSprite(value, font); // textSprite.geometry.computeBoundingBox(); // // const geom = textSprite.geometry, // width = geom.boundingBox.max.x - geom.boundingBox.min.x; // // // textSprite.position.set(-300, 0, 0); // // textSprite.position.set(-300, 0, -sphere.radius); // textSprite.position.set(-300, -width / 2, width / 2); // textSprite.lookAt(scene.position); // // scene.add(textSprite); // // return textSprite; // } setup(function start (cfg) { let rootelem = getrootelem(), windowwh = getwindowwh(), pwwindow = pixelweight(window), // countnum, panelmesharr, // countsprite, floormesh = getfloormesh(), fuseduration = 3, canvasscene = getscene({ xcolor : cfg.trackballxcolor, ycolor : cfg.trackballycolor, zcolor : cfg.trackballzcolor, fgcolor : cfg.trackballfgcolor, bgcolor : cfg.trackballbgcolor, bgskycolor : cfg.bgskycolor, bgskyimg : cfg.bgskyimg // bgtexturecolor : cfg.bgtexturecolor }, appendchild(rootelem, getcanvaselem({ wh : windowwh }))); // add cube panelmesharr = cfg.panels.map(panelcfg => { let panelmesh = getpanelmesh(panelcfg); Object.assign(panelmesh.position, panelcfg.position); Object.assign(panelmesh.rotation, panelcfg.rotation); return panelmesh; }); panelmesharr.map(panelmesh => canvasscene.glscene.add(panelmesh)); Object.assign(floormesh.position, { x : 0, y : -300, z : 0 }); canvasscene.glscene.add( readyaim.three.getscaleimgsprite(THREE, { imgsrc : './img/square-crosshair-empty.png', color : 0xffffff, scale : [ 4, 4 ] })); canvasscene.aimstate = readyaim(THREE, canvasscene.camera, { proximity : false, clickevents : true, near : null, far : null, reticle : { visible : true, // Defines the reticle's resting point when no object has been targeted restPoint : 1000, color : 0xffffff, innerRadius : 0.0001, outerRadius : 0.003, hoverColor : 0xffffff, hoverInnerRadius : 0.02, hoverOuterRadius : 0.024, hoverSpeed : 5, hoverVibrate : 50 }, fuse : { visible : true, duration : fuseduration, color : 0xffffff, innerRadius : 0.045, outerRadius : 0.06, vibrate : 100, // does click cancel targeted fuse? clickCancel : false } }); panelmesharr.map(panelmesh => ( canvasscene.aimstate = readyaim.addmesh(THREE, canvasscene.aimstate, panelmesh, { reticle : { // Override global reticle hoverColor : 0xffffff }, fuse : { // Override global fuse visible : true, duration : fuseduration, color : 0xffffff } }))); rootelem.id = 'id-is-required'; readyaim.attach(canvasscene.aimstate, rootelem, { oneventfn : (cfg, etype, mesh) => { if (etype === readyaim.events.GAZELONG) { mesh.material.emissive.setHex(0x0000cc); // if (countsprite) // canvasscene.glscene.remove(countsprite); console.log('[...] called: onGazeLong'); } if (etype === readyaim.events.GAZEOUT) { mesh.material.emissive.setHex(0xcc0000); // if (countsprite) // canvasscene.glscene.remove(countsprite); console.log('[...] called: onGazeOut'); } if (etype === readyaim.events.GAZEOVER) { mesh.material.emissive.setHex(0xffcc00); // countnum = String(fuseduration); // countsprite = countadd(String(countnum), font, canvasscene.glscene); console.log('[...] called: onGazeOver'); } if (etype === readyaim.events.GAZECLICK) { mesh.material.emissive.setHex(0x0000cc); console.log('[...] called: onGazeClick'); } } // ongazefn : (cfg, intersectts, mesh) => { // let delta = (Date.now() - intersectts) / 1000, // nextcount = Math.ceil(fuseduration - delta); // // if (nextcount !== countnum) { // if (countsprite) // canvasscene.glscene.remove(countsprite); // // countnum = nextcount; // countsprite = countadd(String(countnum), font, canvasscene.glscene); // } // } }); rootelem.id = 'id-is-required'; touchboom.attach(cfg, rootelem, { oninertiafn : cfg => { let totalxy = touchboom.coordsgettotal(cfg), [ radx, rady ] = totalxy.map(px => pixeltodegree(px, pwwindow) ).map(degreetoradian); canvasscene.headgroup.rotation.x = -rady; canvasscene.bodygroup.rotation.y = radx; } }); (function animate () { canvasscene.glrenderer.render( canvasscene.glscene, canvasscene.camera); canvasscene.aimstate = readyaim.update(canvasscene.aimstate); requestAnimationFrame(animate); }()); }, { fontpath : './font/helvetiker_regular.typeface.json', wh : [ window.innerWidth, window.innerHeight ], bgtextcolor : 'rgb(250, 200, 30)', bgskycolor : 'rgb(30, 90, 120)', // bgskyimg : './img/armenia.jpg', // bgskyimg : './img/retrowave_neon_80_s_background___4k_by_rafael_de_jongh-dbk7ro6.jpg', // bgskyimg : './img/wallhaven-477266.jpg', panels : [ { color : 'rgb(255, 255, 140)', position : { x : -300, y : -150, z : 100 }, rotation : { x : 0, y : 0, z : 0 } }, { color : 'rgb(255, 100, 100)', position : { x : -300, y : -150, z : -100 }, rotation : { x : 0, y : 0, z : 0 } } ] });