From 8a30ed0c1c0a7d946c77ce032e123de6efec6848 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Mon, 25 Mar 2024 10:24:02 +0900 Subject: [PATCH] EnvironmentControls: add plane fallback (#516) * Use environment controls in fade example * Update raycasting * Add fallback plane * Add comment --- example/fadingTiles.js | 19 ++++----- src/three/controls/EnvironmentControls.js | 48 ++++++++++++++++++----- src/three/controls/GlobeControls.js | 1 + 3 files changed, 47 insertions(+), 21 deletions(-) diff --git a/example/fadingTiles.js b/example/fadingTiles.js index b72949781..ddc4d7691 100644 --- a/example/fadingTiles.js +++ b/example/fadingTiles.js @@ -1,6 +1,3 @@ -import { - FadeTilesRenderer, -} from './src/FadeTilesRenderer.js'; import { Scene, DirectionalLight, @@ -9,7 +6,8 @@ import { PerspectiveCamera, Group, } from 'three'; -import { FlyOrbitControls } from './src/controls/FlyOrbitControls.js'; +import { FadeTilesRenderer, } from './src/FadeTilesRenderer.js'; +import { EnvironmentControls } from '../src/index.js'; import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'; let camera, controls, scene, renderer; @@ -43,17 +41,13 @@ function init() { document.body.appendChild( renderer.domElement ); renderer.domElement.tabIndex = 1; - camera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 4000 ); + camera = new PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.25, 4000 ); camera.position.set( 20, 10, 20 ); // controls - controls = new FlyOrbitControls( camera, renderer.domElement ); - controls.screenSpacePanning = false; - controls.minDistance = 1; - controls.maxDistance = 2000; - controls.maxPolarAngle = Math.PI / 2; - controls.baseSpeed = 0.1; - controls.fastSpeed = 0.2; + controls = new EnvironmentControls( scene, camera, renderer.domElement ); + controls.minZoomDistance = 2; + controls.cameraRadius = 1; // lights const dirLight = new DirectionalLight( 0xffffff ); @@ -123,6 +117,7 @@ function render() { requestAnimationFrame( render ); + controls.update(); camera.updateMatrixWorld(); groundTiles.errorTarget = params.errorTarget; diff --git a/src/three/controls/EnvironmentControls.js b/src/three/controls/EnvironmentControls.js index 38f981d65..81d17dc57 100644 --- a/src/three/controls/EnvironmentControls.js +++ b/src/three/controls/EnvironmentControls.js @@ -108,6 +108,9 @@ export class EnvironmentControls extends EventDispatcher { this.up = new Vector3( 0, 1, 0 ); + this.fallbackPlane = new Plane( new Vector3( 0, 1, 0 ), 0 ); + this.useFallbackPlane = true; + this._detachCallback = null; this._upInitialized = false; @@ -180,7 +183,6 @@ export class EnvironmentControls extends EventDispatcher { camera, raycaster, domElement, - scene, up, pivotMesh, pointerTracker, @@ -215,7 +217,7 @@ export class EnvironmentControls extends EventDispatcher { // find the hit point raycaster.setFromCamera( _pointer, camera ); - const hit = raycaster.intersectObject( scene )[ 0 ] || null; + const hit = this._raycast( raycaster ); if ( hit ) { // if two fingers, right click, or shift click are being used then we trigger @@ -636,10 +638,9 @@ export class EnvironmentControls extends EventDispatcher { const finalZoomDirection = _vec.copy( zoomDirection ); // always update the zoom target point in case the tiles are changing - let dist = Infinity; if ( this._updateZoomPoint() ) { - dist = zoomPoint.distanceTo( camera.position ); + const dist = zoomPoint.distanceTo( camera.position ); // scale the distance based on how far there is to move if ( scale < 0 ) { @@ -665,7 +666,7 @@ export class EnvironmentControls extends EventDispatcher { const hit = this._getPointBelowCamera(); if ( hit ) { - dist = hit.distance; + const dist = hit.distance; finalZoomDirection.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); camera.position.addScaledVector( finalZoomDirection, scale * dist * 0.01 ); camera.updateMatrixWorld(); @@ -684,7 +685,6 @@ export class EnvironmentControls extends EventDispatcher { zoomDirectionSet, zoomDirection, raycaster, - scene, zoomPoint, } = this; @@ -697,7 +697,7 @@ export class EnvironmentControls extends EventDispatcher { raycaster.ray.origin.copy( camera.position ); raycaster.ray.direction.copy( zoomDirection ); - const hit = raycaster.intersectObject( scene )[ 0 ] || null; + const hit = this._raycast( raycaster ); if ( hit ) { zoomPoint.copy( hit.point ); @@ -713,11 +713,11 @@ export class EnvironmentControls extends EventDispatcher { // returns the point below the camera _getPointBelowCamera() { - const { camera, raycaster, scene, up } = this; + const { camera, raycaster, up } = this; raycaster.ray.direction.copy( up ).multiplyScalar( - 1 ); raycaster.ray.origin.copy( camera.position ).addScaledVector( up, 1e5 ); - const hit = raycaster.intersectObject( scene )[ 0 ] || null; + const hit = this._raycast( raycaster ); if ( hit ) { hit.distance -= 1e5; @@ -907,4 +907,34 @@ export class EnvironmentControls extends EventDispatcher { } + _raycast( raycaster ) { + + const { scene, useFallbackPlane, fallbackPlane } = this; + const result = raycaster.intersectObject( scene )[ 0 ] || null; + if ( result ) { + + return result; + + } else if ( useFallbackPlane ) { + + // if we don't hit any geometry then try to intersect the fallback + // plane so the camera can still be manipulated + const plane = fallbackPlane; + if ( raycaster.ray.intersectPlane( plane, _vec ) ) { + + const planeHit = { + point: _vec.clone(), + distance: raycaster.ray.origin.distanceTo( _vec ), + }; + + return planeHit; + + } + + } + + return null; + + } + } diff --git a/src/three/controls/GlobeControls.js b/src/three/controls/GlobeControls.js index 4bfb9a6d6..e50524c0d 100644 --- a/src/three/controls/GlobeControls.js +++ b/src/three/controls/GlobeControls.js @@ -49,6 +49,7 @@ export class GlobeControls extends EnvironmentControls { this._tilesRenderer = null; this._dragMode = 0; this._rotationMode = 0; + this.useFallbackPlane = false; this.setTilesRenderer( tilesRenderer );