xzw 2 سال پیش
والد
کامیت
bcafd538fb
4فایلهای تغییر یافته به همراه665 افزوده شده و 20 حذف شده
  1. 7 13
      src/custom/note.txt
  2. 5 6
      src/navigation/VRControls.js
  3. 652 0
      src/navigation/VRControlsNew.js
  4. 1 1
      src/viewer/HQSplatRenderer.js

+ 7 - 13
src/custom/note.txt

@@ -1,4 +1,9 @@
-主文件:Potree.js 
+主文件:Potree.js   该文件随便改
+
+
+viewer现在直接使用ViewerNew.js.  之前写过一个不完全的ExtendViewer,去除了sidebar等功能。
+ 
+libs文件里都没还原
 
 
 
@@ -11,18 +16,8 @@ start.js除了通过引用shim文件来修改Potree, 也可在此文件修改,
 问题:
 
  
-
-----
-因为viewer太复杂了就去掉了所有和sidebar有关的代码(没完全继承原先的viewer的函数)。也就是说不支持非official的情况(no sidebar)。需要用这个测试的需要换分支。
-鉴于经常要测试,需要保持两个分支代码同步更新。
-libs文件里都没还原
-
-Potree.js文件随便改
  
 
-
-vr也被去掉。(webxr) https://potree.org/potree/examples/vr_dechen_cave.html 可调
-
 ======================
 
 bug:
@@ -43,8 +38,7 @@ bug:
 Volume.js   VolumeTool.js  我原本在构造函数去掉了一些不用的内容,现在恢复了,如果报错再删掉
 
 
-
-有一些注释我暂时删掉了  过后校验新文件时补一下
+ 
 
 
 ===============================

+ 5 - 6
src/navigation/VRControls.js

@@ -1,11 +1,11 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js"; 
+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";
-import {EventDispatcher} from "../EventDispatcher.js";
-
+//old
 let fakeCam = new THREE.PerspectiveCamera();
 
 function toScene(vec, ref){
@@ -74,11 +74,10 @@ class FlyMode{
 
 	start(vrControls){
 		if(!this.dbgLabel){
-			debugger;
-			/* this.dbgLabel = new Potree.TextSprite("abc");
+			this.dbgLabel = new Potree.TextSprite("abc");
 			this.dbgLabel.name = "debug label";
 			vrControls.viewer.sceneVR.add(this.dbgLabel);
-			this.dbgLabel.visible = false; */
+			this.dbgLabel.visible = false;
 		}
 	}
 	

+ 652 - 0
src/navigation/VRControlsNew.js

@@ -0,0 +1,652 @@
+
+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";
+
+import {GLTFLoader} from  "../../libs/three.js/loaders/GLTFLoader.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){
+			debugger;
+			/* 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({target:sceneTarget, position:scenePos})
+        
+        
+		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(new GLTFLoader(undefined, viewer.renderer, Potree.settings.libsUrl ));
+
+		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);
+
+		
+
+	}
+};

+ 1 - 1
src/viewer/HQSplatRenderer.js

@@ -7,7 +7,7 @@ import {PointShape} from "../defines.js";
 import {SphereVolume} from "../utils/Volume.js";
 import {Utils} from "../utils.js";
 
-//在potree.shim中修改。。official中用不到
+//在potree.shim中修改。 。official中用不到且有bug
 export class HQSplatRenderer{
 	
 	constructor(viewer){