@@ -6,6 +6,7 @@ import { VRButton } from 'https://unpkg.com/three@0.153.0/examples/jsm/webxr/VRB
66import { LineMaterial } from 'https://unpkg.com/three@0.153.0/examples/jsm/lines/LineMaterial.js'
77import { Line2 } from 'https://unpkg.com/three@0.153.0/examples/jsm/lines/Line2.js'
88import { LineGeometry } from 'https://unpkg.com/three@0.153.0/examples/jsm/lines/LineGeometry.js'
9+ import { XRControllerModelFactory } from 'https://unpkg.com/three@0.153.0/examples/jsm/webxr/XRControllerModelFactory.js' ;
910import 'https://cdn.jsdelivr.net/npm/robust-websocket@1.0.0/robust-websocket.min.js' ;
1011
1112class TesseractViewer {
@@ -31,6 +32,17 @@ class TesseractViewer {
3132 this . _update_trajectory_timer = null ;
3233 this . _update_markers_timer = null ;
3334 this . _update_scene_timer = null ;
35+ this . _xr_dolly = null ;
36+ this . _xr_controller1_grip = null ;
37+ this . _xr_controller2_grip = null ;
38+ this . _xr_controller1_model = null ;
39+ this . _xr_controller2_model = null ;
40+ this . _xr_gamepad1 = null ;
41+ this . _xr_gamepad2 = null ;
42+ this . _controls = null ;
43+ this . _xr_drag_controller_start = null ;
44+ this . _xr_drag_controller_orientation = null ;
45+ this . _xr_drag_dolly_start = null ;
3446
3547 }
3648
@@ -39,9 +51,7 @@ class TesseractViewer {
3951 this . _clock = new THREE . Clock ( ) ;
4052
4153 const camera = new THREE . PerspectiveCamera ( 45 , window . innerWidth / window . innerHeight , 0.1 , 1000 ) ;
42- camera . position . x = 3 ;
43- camera . position . y = 3 ;
44- camera . position . z = - 1.5 ;
54+ camera . position . set ( 3 , 3 , - 1.5 )
4555 this . _camera = camera ;
4656
4757 const renderer = new THREE . WebGLRenderer ( { antialias : true } ) ;
@@ -71,14 +81,20 @@ class TesseractViewer {
7181
7282 document . body . appendChild ( renderer . domElement ) ;
7383
74- const controls = new OrbitControls ( camera , renderer . domElement ) ;
84+ this . _controls = new OrbitControls ( camera , renderer . domElement ) ;
85+
86+ let _this = this ;
7587
7688 // Only add VR button if it is supported
7789 if ( 'xr' in navigator )
7890 {
7991 if ( await navigator . xr . isSessionSupported ( 'immersive-vr' ) )
8092 {
8193 document . body . appendChild ( VRButton . createButton ( renderer ) ) ;
94+
95+ renderer . xr . addEventListener ( 'sessionstart' , function ( ) {
96+ _this . enterXR ( ) ;
97+ } ) ;
8298 }
8399 }
84100
@@ -101,7 +117,6 @@ class TesseractViewer {
101117
102118 await this . updateScene ( ) ;
103119
104- let _this = this ;
105120 const queryString = window . location . search ;
106121 const urlParams = new URLSearchParams ( queryString ) ;
107122 let do_update = true ;
@@ -119,7 +134,19 @@ class TesseractViewer {
119134
120135 createWebSocket ( ) {
121136 // Create a new WebSocket instance
122- const socket = new RobustWebSocket ( 'ws://localhost:8000/websocket' , null , {
137+
138+ // Get host and port from current URL
139+ const host = window . location . hostname ;
140+ const port = window . location . port ;
141+ let ws_protocol = "ws" ;
142+
143+ if ( window . location . protocol === "https:" ) {
144+ ws_protocol = "wss" ;
145+ }
146+
147+ const ws_url = ws_protocol + "://" + host + ":" + port + "/websocket" ;
148+
149+ const socket = new RobustWebSocket ( ws_url , null , {
123150 shouldReconnect : ( event , ws ) => { return 1000 ; }
124151 } ) ;
125152
@@ -157,7 +184,9 @@ class TesseractViewer {
157184
158185 var delta = this . _clock . getDelta ( ) ;
159186 if ( this . _animation_mixer ) this . _animation_mixer . update ( delta ) ;
160- } ;
187+
188+ this . xrLocomotion ( ) ;
189+ }
161190
162191 async fetchIfModified ( url , etag ) {
163192 let fetch_res ;
@@ -704,8 +733,147 @@ class TesseractViewer {
704733 tf . parent . remove ( tf ) ;
705734 } ) ;
706735 }
736+
737+ initXRControllers ( dolly ) {
738+ const controller1 = this . _renderer . xr . getController ( 0 ) ;
739+ const controller2 = this . _renderer . xr . getController ( 1 ) ;
740+
741+ dolly . add ( controller1 ) ;
742+ dolly . add ( controller2 ) ;
743+
744+ const controllerModelFactory = new XRControllerModelFactory ( ) ;
745+
746+ const controllerGrip1 = this . _renderer . xr . getControllerGrip ( 0 ) ;
747+ this . _xr_controller1_grip = controllerGrip1 ;
748+ this . _xr_controller1_model = controllerModelFactory . createControllerModel ( controllerGrip1 ) ;
749+ controllerGrip1 . add ( this . _xr_controller1_model ) ;
750+ dolly . add ( controllerGrip1 ) ;
751+
752+ const controllerGrip2 = this . _renderer . xr . getControllerGrip ( 1 ) ;
753+ this . _xr_controller2_grip = controllerGrip2 ;
754+ this . _xr_controller2_model = controllerModelFactory . createControllerModel ( controllerGrip2 ) ;
755+ controllerGrip2 . add ( this . _xr_controller2_model ) ;
756+ dolly . add ( controllerGrip2 ) ;
757+
758+ let _this = this ;
759+
760+ controllerGrip1 . addEventListener ( "connected" , ( e ) => {
761+ _this . _xr_gamepad1 = e . data . gamepad ;
762+ } )
763+
764+ controllerGrip2 . addEventListener ( "connected" , ( e ) => {
765+ _this . _xr_gamepad2 = e . data . gamepad ;
766+ } )
767+ }
768+
769+ enterXR ( ) {
770+ this . _controls . saveState ( ) ;
771+ this . _xr_dolly = new THREE . Object3D ( ) ;
772+ this . initXRControllers ( this . _xr_dolly )
773+ this . _xr_dolly . add ( this . _camera ) ;
774+ this . _camera . position . set ( 0 , 0 , 0 ) ;
775+ this . _camera . rotation . set ( 0 , 0 , 0 ) ;
776+ this . _scene . add ( this . _xr_dolly ) ;
777+ this . _xr_dolly . position . set ( 2.5 , 0 , 0 ) ;
778+ this . _xr_dolly . rotateY ( Math . PI / 2.0 ) ;
779+
780+ this . _renderer . xr . getSession ( ) . addEventListener ( 'end' , ( ) => {
781+ this . _scene . add ( this . _camera ) ;
782+ this . _scene . remove ( this . _xr_dolly ) ;
783+ this . _xr_dolly . remove ( this . _camera ) ;
784+ this . _xr_dolly = null ;
785+ this . _xr_controller1_grip . remove ( this . _xr_controller1_model ) ;
786+ this . _xr_controller2_grip . remove ( this . _xr_controller2_model ) ;
787+ this . _xr_controller1_grip = null ;
788+ this . _xr_controller2_grip = null ;
789+ this . _xr_controller1_model = null ;
790+ this . _xr_controller2_model = null ;
791+ this . _controls . reset ( ) ;
792+ this . _controls . update ( ) ;
793+ } ) ;
794+
795+
796+ }
797+
798+ xrLocomotion ( )
799+ {
800+ if ( this . _xr_dolly && this . _xr_gamepad2 ) {
801+ try
802+ {
803+
804+ if ( this . _xr_gamepad2 . buttons [ 5 ] . pressed )
805+ {
806+ if ( ! this . _xr_drag_controller_start )
807+ {
808+ this . _xr_drag_controller_start = this . _xr_controller2_grip . position . clone ( ) ;
809+ let world_quat = new THREE . Quaternion ( ) ;
810+ this . _xr_drag_controller_orientation = this . _camera . getWorldQuaternion ( world_quat ) ;
811+
812+ this . _xr_drag_dolly_start = this . _xr_dolly . position . clone ( ) ;
813+ }
814+
815+ let controller_diff = this . _xr_controller2_grip . position . clone ( ) . sub ( this . _xr_drag_controller_start ) ;
816+ controller_diff . applyQuaternion ( this . _xr_drag_controller_orientation . clone ( ) ) ;
817+ let y_diff = controller_diff . y ;
818+ y_diff = Math . floor ( y_diff / 0.1 ) ;
819+ if ( y_diff < 0 ) {
820+ y_diff = y_diff + 1 ;
821+ }
822+ controller_diff . y = y_diff * 0.1 ;
823+ let dolly_pos = this . _xr_drag_dolly_start . clone ( ) . sub ( controller_diff ) ;
824+ this . _xr_dolly . position . copy ( dolly_pos ) ;
825+ }
826+ else
827+ {
828+ if ( this . _xr_drag_controller_start )
829+ {
830+ this . _xr_drag_controller_start = null ;
831+ this . _xr_drag_dolly_start = null ;
832+ }
833+ }
834+
835+ }
836+ catch ( e )
837+ {
838+ console . log ( e ) ;
839+ }
840+
841+ if ( this . _xr_gamepad2 . axes . length == 4 ) {
842+ let axis_2 = this . _xr_gamepad2 . axes [ 2 ] ;
843+ if ( axis_2 > 0.2 )
844+ {
845+ let scale = - ( axis_2 - 0.2 ) / 0.8 ;
846+ this . _xr_dolly . rotateY ( 0.01 * scale ) ;
847+ }
848+ if ( axis_2 < - 0.2 )
849+ {
850+ let scale = - ( axis_2 + 0.2 ) / 0.8 ;
851+ this . _xr_dolly . rotateY ( 0.01 * scale ) ;
852+ }
853+
854+ let axis_3 = this . _xr_gamepad2 . axes [ 3 ] ;
855+ let dolly_world_quat = new THREE . Quaternion ( ) ;
856+ this . _xr_dolly . getWorldQuaternion ( dolly_world_quat ) ;
857+ let dolly_forward = new THREE . Vector3 ( 0 , 0 , - 1 ) ;
858+ dolly_forward . applyQuaternion ( dolly_world_quat ) ;
859+
860+ if ( axis_3 > 0.2 )
861+ {
862+ let scale = - ( axis_3 - 0.2 ) / 0.8 ;
863+ this . _xr_dolly . position . add ( dolly_forward . clone ( ) . multiplyScalar ( 0.01 * scale ) ) ;
864+ }
865+ if ( axis_3 < - 0.2 )
866+ {
867+ let scale = - ( axis_3 + 0.2 ) / 0.8 ;
868+ this . _xr_dolly . position . add ( dolly_forward . clone ( ) . multiplyScalar ( 0.01 * scale ) ) ;
869+ }
870+ }
871+ }
872+ } ;
707873}
708874
875+
876+
709877window . addEventListener ( "DOMContentLoaded" , async function ( ) {
710878 let viewer = new TesseractViewer ( ) ;
711879 window . tesseract_viewer = viewer ;
0 commit comments