123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647 |
- import * as THREE from "../../libs/three.js/build/three.module.js";
- import {EventDispatcher} from "../EventDispatcher.js";
- import { XRControllerModelFactory } from '../../libs/three.js/webxr/XRControllerModelFactory.js';
- import {Line2} from "../../libs/three.js/lines/Line2.js";
- import {LineGeometry} from "../../libs/three.js/lines/LineGeometry.js";
- import {LineMaterial} from "../../libs/three.js/lines/LineMaterial.js";
- let fakeCam = new THREE.PerspectiveCamera();
- function toScene(vec, ref){
- let node = ref.clone();
- node.updateMatrix();
- node.updateMatrixWorld();
- let result = vec.clone().applyMatrix4(node.matrix);
- result.z -= 0.8 * node.scale.x;
- return result;
- };
- function computeMove(vrControls, controller){
- if(!controller || !controller.inputSource || !controller.inputSource.gamepad){
- return null;
- }
- let pad = controller.inputSource.gamepad;
- let axes = pad.axes;
- // [0,1] are for touchpad, [2,3] for thumbsticks?
- let y = 0;
- if(axes.length === 2){
- y = axes[1];
- }else if(axes.length === 4){
- y = axes[3];
- }
- y = Math.sign(y) * (2 * y) ** 2;
- let maxSize = 0;
- for(let pc of viewer.scene.pointclouds){
- let size = pc.boundingBox.min.distanceTo(pc.boundingBox.max);
- maxSize = Math.max(maxSize, size);
- }
- let multiplicator = Math.pow(maxSize, 0.5) / 2;
- let scale = vrControls.node.scale.x;
- let moveSpeed = viewer.getMoveSpeed();
- let amount = multiplicator * y * (moveSpeed ** 0.5) / scale;
- let rotation = new THREE.Quaternion().setFromEuler(controller.rotation);
- let dir = new THREE.Vector3(0, 0, -1);
- dir.applyQuaternion(rotation);
- let move = dir.clone().multiplyScalar(amount);
- let p1 = vrControls.toScene(controller.position);
- let p2 = vrControls.toScene(controller.position.clone().add(move));
- move = p2.clone().sub(p1);
-
- return move;
- };
- class FlyMode{
- constructor(vrControls){
- this.moveFactor = 1;
- this.dbgLabel = null;
- }
- start(vrControls){
- if(!this.dbgLabel){
- /* this.dbgLabel = new Potree.TextSprite("abc");
- this.dbgLabel.name = "debug label";
- vrControls.viewer.sceneVR.add(this.dbgLabel);
- this.dbgLabel.visible = false; */
- }
- }
-
- end(){
- }
- update(vrControls, delta){
- let primary = vrControls.cPrimary;
- let secondary = vrControls.cSecondary;
- let move1 = computeMove(vrControls, primary);
- let move2 = computeMove(vrControls, secondary);
- if(!move1){
- move1 = new THREE.Vector3();
- }
- if(!move2){
- move2 = new THREE.Vector3();
- }
- let move = move1.clone().add(move2);
- move.multiplyScalar(-delta * this.moveFactor);
- vrControls.node.position.add(move);
-
- let scale = vrControls.node.scale.x;
- let camVR = vrControls.viewer.renderer.xr.getCamera(fakeCam);
-
- let vrPos = camVR.getWorldPosition(new THREE.Vector3());
- let vrDir = camVR.getWorldDirection(new THREE.Vector3());
- let vrTarget = vrPos.clone().add(vrDir.multiplyScalar(scale));
- let scenePos = toScene(vrPos, vrControls.node);
- let sceneDir = toScene(vrPos.clone().add(vrDir), vrControls.node).sub(scenePos);
- sceneDir.normalize().multiplyScalar(scale);
- let sceneTarget = scenePos.clone().add(sceneDir);
- vrControls.viewer.scene.view.setView(scenePos, sceneTarget);
- if(Potree.debug.message){
- this.dbgLabel.visible = true;
- this.dbgLabel.setText(Potree.debug.message);
- this.dbgLabel.scale.set(0.1, 0.1, 0.1);
- this.dbgLabel.position.copy(primary.position);
- }
- }
- };
- class TranslationMode{
- constructor(){
- this.controller = null;
- this.startPos = null;
- this.debugLine = null;
- }
- start(vrControls){
- this.controller = vrControls.triggered.values().next().value;
- this.startPos = vrControls.node.position.clone();
- }
-
- end(vrControls){
- }
- update(vrControls, delta){
- let start = this.controller.start.position;
- let end = this.controller.position;
- start = vrControls.toScene(start);
- end = vrControls.toScene(end);
- let diff = end.clone().sub(start);
- diff.set(-diff.x, -diff.y, -diff.z);
- let pos = new THREE.Vector3().addVectors(this.startPos, diff);
- vrControls.node.position.copy(pos);
- }
- };
- class RotScaleMode{
- constructor(){
- this.line = null;
- this.startState = null;
- }
- start(vrControls){
- if(!this.line){
- this.line = Potree.Utils.debugLine(
- vrControls.viewer.sceneVR,
- new THREE.Vector3(0, 0, 0),
- new THREE.Vector3(0, 0, 0),
- 0xffff00,
- );
- this.dbgLabel = new Potree.TextSprite("abc");
- this.dbgLabel.scale.set(0.1, 0.1, 0.1);
- vrControls.viewer.sceneVR.add(this.dbgLabel);
- }
- this.line.node.visible = true;
- this.startState = vrControls.node.clone();
- }
- end(vrControls){
- this.line.node.visible = false;
- this.dbgLabel.visible = false;
- }
- update(vrControls, delta){
- let start_c1 = vrControls.cPrimary.start.position.clone();
- let start_c2 = vrControls.cSecondary.start.position.clone();
- let start_center = start_c1.clone().add(start_c2).multiplyScalar(0.5);
- let start_c1_c2 = start_c2.clone().sub(start_c1);
- let end_c1 = vrControls.cPrimary.position.clone();
- let end_c2 = vrControls.cSecondary.position.clone();
- let end_center = end_c1.clone().add(end_c2).multiplyScalar(0.5);
- let end_c1_c2 = end_c2.clone().sub(end_c1);
- let d1 = start_c1_c2.length();
- let d2 = end_c1_c2.length();
- let angleStart = new THREE.Vector2(start_c1_c2.x, start_c1_c2.z).angle();
- let angleEnd = new THREE.Vector2(end_c1_c2.x, end_c1_c2.z).angle();
- let angleDiff = angleEnd - angleStart;
-
- let scale = d2 / d1;
- let node = this.startState.clone();
- node.updateMatrix();
- node.matrixAutoUpdate = false;
- let mToOrigin = new THREE.Matrix4().makeTranslation(...toScene(start_center, this.startState).multiplyScalar(-1).toArray());
- let mToStart = new THREE.Matrix4().makeTranslation(...toScene(start_center, this.startState).toArray());
- let mRotate = new THREE.Matrix4().makeRotationZ(angleDiff);
- let mScale = new THREE.Matrix4().makeScale(1 / scale, 1 / scale, 1 / scale);
- node.applyMatrix4(mToOrigin);
- node.applyMatrix4(mRotate);
- node.applyMatrix4(mScale);
- node.applyMatrix4(mToStart);
- let oldScenePos = toScene(start_center, this.startState);
- let newScenePos = toScene(end_center, node);
- let toNew = oldScenePos.clone().sub(newScenePos);
- let mToNew = new THREE.Matrix4().makeTranslation(...toNew.toArray());
- node.applyMatrix4(mToNew);
- node.matrix.decompose(node.position, node.quaternion, node.scale );
- vrControls.node.position.copy(node.position);
- vrControls.node.quaternion.copy(node.quaternion);
- vrControls.node.scale.copy(node.scale);
- vrControls.node.updateMatrix();
- {
- let scale = vrControls.node.scale.x;
- let camVR = vrControls.viewer.renderer.xr.getCamera(fakeCam);
-
- let vrPos = camVR.getWorldPosition(new THREE.Vector3());
- let vrDir = camVR.getWorldDirection(new THREE.Vector3());
- let vrTarget = vrPos.clone().add(vrDir.multiplyScalar(scale));
- let scenePos = toScene(vrPos, this.startState);
- let sceneDir = toScene(vrPos.clone().add(vrDir), this.startState).sub(scenePos);
- sceneDir.normalize().multiplyScalar(scale);
- let sceneTarget = scenePos.clone().add(sceneDir);
- vrControls.viewer.scene.view.setView(scenePos, sceneTarget);
- vrControls.viewer.setMoveSpeed(scale);
- }
- { // update "GUI"
- this.line.set(end_c1, end_c2);
- let scale = vrControls.node.scale.x;
- this.dbgLabel.visible = true;
- this.dbgLabel.position.copy(end_center);
- this.dbgLabel.setText(`scale: 1 : ${scale.toFixed(2)}`);
- this.dbgLabel.scale.set(0.05, 0.05, 0.05);
- }
- }
- };
- export class VRControls extends EventDispatcher{
- constructor(viewer){
- super(viewer);
- this.viewer = viewer;
- viewer.addEventListener("vr_start", this.onStart.bind(this));
- viewer.addEventListener("vr_end", this.onEnd.bind(this));
- this.node = new THREE.Object3D();
- this.node.up.set(0, 0, 1);
- this.triggered = new Set();
- let xr = viewer.renderer.xr;
- { // lights
-
- const light = new THREE.PointLight( 0xffffff, 5, 0, 1 );
- light.position.set(0, 2, 0);
- this.viewer.sceneVR.add(light)
- }
- this.menu = null;
- const controllerModelFactory = new XRControllerModelFactory();
- let sg = new THREE.SphereGeometry(1, 32, 32);
- let sm = new THREE.MeshNormalMaterial();
- { // setup primary controller
- let controller = xr.getController(0);
- let grip = xr.getControllerGrip(0);
- grip.name = "grip(0)";
- // ADD CONTROLLERMODEL
- grip.add( controllerModelFactory.createControllerModel( grip ) );
- this.viewer.sceneVR.add(grip);
- // ADD SPHERE
- let sphere = new THREE.Mesh(sg, sm);
- sphere.scale.set(0.005, 0.005, 0.005);
- controller.add(sphere);
- controller.visible = true;
- this.viewer.sceneVR.add(controller);
- { // ADD LINE
-
- let lineGeometry = new LineGeometry();
- lineGeometry.setPositions([
- 0, 0, -0.15,
- 0, 0, 0.05,
- ]);
- let lineMaterial = new LineMaterial({
- color: 0xff0000,
- linewidth: 2,
- resolution: new THREE.Vector2(1000, 1000),
- });
- const line = new Line2(lineGeometry, lineMaterial);
-
- controller.add(line);
- }
- controller.addEventListener( 'connected', function ( event ) {
- const xrInputSource = event.data;
- controller.inputSource = xrInputSource;
- // initInfo(controller);
- });
- controller.addEventListener( 'selectstart', () => {this.onTriggerStart(controller)});
- controller.addEventListener( 'selectend', () => {this.onTriggerEnd(controller)});
- this.cPrimary = controller;
- }
- { // setup secondary controller
- let controller = xr.getController(1);
- let grip = xr.getControllerGrip(1);
- // ADD CONTROLLER MODEL
- let model = controllerModelFactory.createControllerModel( grip );
- grip.add(model);
- this.viewer.sceneVR.add( grip );
- // ADD SPHERE
- let sphere = new THREE.Mesh(sg, sm);
- sphere.scale.set(0.005, 0.005, 0.005);
- controller.add(sphere);
- controller.visible = true;
- this.viewer.sceneVR.add(controller);
- { // ADD LINE
-
- let lineGeometry = new LineGeometry();
- lineGeometry.setPositions([
- 0, 0, -0.15,
- 0, 0, 0.05,
- ]);
- let lineMaterial = new LineMaterial({
- color: 0xff0000,
- linewidth: 2,
- resolution: new THREE.Vector2(1000, 1000),
- });
- const line = new Line2(lineGeometry, lineMaterial);
-
- controller.add(line);
- }
- controller.addEventListener( 'connected', (event) => {
- const xrInputSource = event.data;
- controller.inputSource = xrInputSource;
- this.initMenu(controller);
- });
- controller.addEventListener( 'selectstart', () => {this.onTriggerStart(controller)});
- controller.addEventListener( 'selectend', () => {this.onTriggerEnd(controller)});
- this.cSecondary = controller;
- }
- this.mode_fly = new FlyMode();
- this.mode_translate = new TranslationMode();
- this.mode_rotScale = new RotScaleMode();
- this.setMode(this.mode_fly);
- }
- createSlider(label, min, max){
- let sg = new THREE.SphereGeometry(1, 8, 8);
- let cg = new THREE.CylinderGeometry(1, 1, 1, 8);
- let matHandle = new THREE.MeshBasicMaterial({color: 0xff0000});
- let matScale = new THREE.MeshBasicMaterial({color: 0xff4444});
- let matValue = new THREE.MeshNormalMaterial();
- let node = new THREE.Object3D("slider");
- let nLabel = new Potree.TextSprite(`${label}: 0`);
- let nMax = new THREE.Mesh(sg, matHandle);
- let nMin = new THREE.Mesh(sg, matHandle);
- let nValue = new THREE.Mesh(sg, matValue);
- let nScale = new THREE.Mesh(cg, matScale);
- nLabel.scale.set(0.2, 0.2, 0.2);
- nLabel.position.set(0, 0.35, 0);
- nMax.scale.set(0.02, 0.02, 0.02);
- nMax.position.set(0, 0.25, 0);
- nMin.scale.set(0.02, 0.02, 0.02);
- nMin.position.set(0, -0.25, 0);
- nValue.scale.set(0.02, 0.02, 0.02);
- nValue.position.set(0, 0, 0);
- nScale.scale.set(0.005, 0.5, 0.005);
- node.add(nLabel);
- node.add(nMax);
- node.add(nMin);
- node.add(nValue);
- node.add(nScale);
- return node;
- }
- createInfo(){
- let texture = new THREE.TextureLoader().load(`${Potree.resourcePath}/images/vr_controller_help.jpg`);
- let plane = new THREE.PlaneBufferGeometry(1, 1, 1, 1);
- let infoMaterial = new THREE.MeshBasicMaterial({map: texture});
- let infoNode = new THREE.Mesh(plane, infoMaterial);
- return infoNode;
- }
- initMenu(controller){
- if(this.menu){
- return;
- }
- let node = new THREE.Object3D("vr menu");
- // let nSlider = this.createSlider("speed", 0, 1);
- // let nInfo = this.createInfo();
- // // node.add(nSlider);
- // node.add(nInfo);
- // {
- // node.rotation.set(-1.5, 0, 0)
- // node.scale.set(0.3, 0.3, 0.3);
- // node.position.set(-0.2, -0.002, -0.1)
- // // nInfo.position.set(0.5, 0, 0);
- // nInfo.scale.set(0.8, 0.6, 0);
- // // controller.add(node);
- // }
- // node.position.set(-0.3, 1.2, 0.2);
- // node.scale.set(0.3, 0.2, 0.3);
- // node.lookAt(new THREE.Vector3(0, 1.5, 0.1));
- // this.viewer.sceneVR.add(node);
- this.menu = node;
- // window.vrSlider = nSlider;
- window.vrMenu = node;
- }
- toScene(vec){
- let camVR = this.getCamera();
- let mat = camVR.matrixWorld;
- let result = vec.clone().applyMatrix4(mat);
- return result;
- }
- toVR(vec){
- let camVR = this.getCamera();
- let mat = camVR.matrixWorld.clone();
- mat.invert();
- let result = vec.clone().applyMatrix4(mat);
- return result;
- }
- setMode(mode){
- if(this.mode === mode){
- return;
- }
- if(this.mode){
- this.mode.end(this);
- }
- for(let controller of [this.cPrimary, this.cSecondary]){
- let start = {
- position: controller.position.clone(),
- rotation: controller.rotation.clone(),
- };
- controller.start = start;
- }
-
- this.mode = mode;
- this.mode.start(this);
- }
- onTriggerStart(controller){
- this.triggered.add(controller);
- if(this.triggered.size === 0){
- this.setMode(this.mode_fly);
- }else if(this.triggered.size === 1){
- this.setMode(this.mode_translate);
- }else if(this.triggered.size === 2){
- this.setMode(this.mode_rotScale);
- }
- }
- onTriggerEnd(controller){
- this.triggered.delete(controller);
- if(this.triggered.size === 0){
- this.setMode(this.mode_fly);
- }else if(this.triggered.size === 1){
- this.setMode(this.mode_translate);
- }else if(this.triggered.size === 2){
- this.setMode(this.mode_rotScale);
- }
- }
- onStart(){
- let position = this.viewer.scene.view.position.clone();
- let direction = this.viewer.scene.view.direction;
- direction.multiplyScalar(-1);
- let target = position.clone().add(direction);
- target.z = position.z;
- let scale = this.viewer.getMoveSpeed();
- this.node.position.copy(position);
- this.node.lookAt(target);
- this.node.scale.set(scale, scale, scale);
- this.node.updateMatrix();
- this.node.updateMatrixWorld();
- }
- onEnd(){
-
- }
- setScene(scene){
- this.scene = scene;
- }
- getCamera(){
- let reference = this.viewer.scene.getActiveCamera();
- let camera = new THREE.PerspectiveCamera();
- // let scale = this.node.scale.x;
- let scale = this.viewer.getMoveSpeed();
- //camera.near = 0.01 / scale;
- camera.near = 0.1;
- camera.far = 1000;
- // camera.near = reference.near / scale;
- // camera.far = reference.far / scale;
- camera.up.set(0, 0, 1);
- camera.lookAt(new THREE.Vector3(0, -1, 0));
- camera.updateMatrix();
- camera.updateMatrixWorld();
- camera.position.copy(this.node.position);
- camera.rotation.copy(this.node.rotation);
- camera.scale.set(scale, scale, scale);
- camera.updateMatrix();
- camera.updateMatrixWorld();
- camera.matrixAutoUpdate = false;
- camera.parent = camera;
- return camera;
- }
- update(delta){
-
- // if(this.mode === this.mode_fly){
- // let ray = new THREE.Ray(origin, direction);
-
- // for(let object of this.selectables){
- // if(object.intersectsRay(ray)){
- // object.onHit(ray);
- // }
- // }
- // }
- this.mode.update(this, delta);
-
- }
- };
|