@@ -153,6 +153,8 @@ module.exports.Component = registerComponent('oculus-touch-controls', {
153153 mapping : INPUT_MAPPING ,
154154
155155 bindMethods : function ( ) {
156+ this . onButtonChanged = bind ( this . onButtonChanged , this ) ;
157+ this . onThumbstickMoved = bind ( this . onThumbstickMoved , this ) ;
156158 this . onModelLoaded = bind ( this . onModelLoaded , this ) ;
157159 this . onControllersUpdate = bind ( this . onControllersUpdate , this ) ;
158160 this . checkIfControllerPresent = bind ( this . checkIfControllerPresent , this ) ;
@@ -161,7 +163,6 @@ module.exports.Component = registerComponent('oculus-touch-controls', {
161163
162164 init : function ( ) {
163165 var self = this ;
164- this . onButtonChanged = bind ( this . onButtonChanged , this ) ;
165166 this . onButtonDown = function ( evt ) { onButtonEvent ( evt . detail . id , 'down' , self , self . data . hand ) ; } ;
166167 this . onButtonUp = function ( evt ) { onButtonEvent ( evt . detail . id , 'up' , self , self . data . hand ) ; } ;
167168 this . onButtonTouchStart = function ( evt ) { onButtonEvent ( evt . detail . id , 'touchstart' , self , self . data . hand ) ; } ;
@@ -171,6 +172,7 @@ module.exports.Component = registerComponent('oculus-touch-controls', {
171172 this . previousButtonValues = { } ;
172173 this . rendererSystem = this . el . sceneEl . systems . renderer ;
173174 this . bindMethods ( ) ;
175+ this . triggerEuler = new THREE . Euler ( ) ;
174176 } ,
175177
176178 addEventListeners : function ( ) {
@@ -182,6 +184,7 @@ module.exports.Component = registerComponent('oculus-touch-controls', {
182184 el . addEventListener ( 'touchend' , this . onButtonTouchEnd ) ;
183185 el . addEventListener ( 'axismove' , this . onAxisMoved ) ;
184186 el . addEventListener ( 'model-loaded' , this . onModelLoaded ) ;
187+ el . addEventListener ( 'thumbstickmoved' , this . onThumbstickMoved ) ;
185188 this . controllerEventsActive = true ;
186189 } ,
187190
@@ -194,6 +197,7 @@ module.exports.Component = registerComponent('oculus-touch-controls', {
194197 el . removeEventListener ( 'touchend' , this . onButtonTouchEnd ) ;
195198 el . removeEventListener ( 'axismove' , this . onAxisMoved ) ;
196199 el . removeEventListener ( 'model-loaded' , this . onModelLoaded ) ;
200+ el . removeEventListener ( 'thumbstickmoved' , this . onThumbstickMoved ) ;
197201 this . controllerEventsActive = false ;
198202 } ,
199203
@@ -220,14 +224,13 @@ module.exports.Component = registerComponent('oculus-touch-controls', {
220224 if ( ! data . model ) { return ; }
221225 // Set the controller display model based on the data passed in.
222226 this . displayModel = CONTROLLER_PROPERTIES [ data . controllerType ] || CONTROLLER_PROPERTIES [ CONTROLLER_DEFAULT ] ;
223- // If the developer is asking for auto-detection, see if the displayName can be retrieved to identify the specific unit.
227+ // If the developer is asking for auto-detection, use the retrieved displayName to identify the specific unit.
224228 // This only works for WebVR currently.
225229 if ( data . controllerType === 'auto' ) {
226230 var trackedControlsSystem = this . el . sceneEl . systems [ 'tracked-controls-webvr' ] ;
227231 // WebVR
228232 if ( trackedControlsSystem && trackedControlsSystem . vrDisplay ) {
229233 var displayName = trackedControlsSystem . vrDisplay . displayName ;
230- // The Oculus Quest uses the updated generation 2 inside-out tracked controllers so update the displayModel.
231234 if ( / ^ O c u l u s Q u e s t $ / . test ( displayName ) ) {
232235 this . displayModel = CONTROLLER_PROPERTIES [ 'oculus-touch-v2' ] ;
233236 }
@@ -239,6 +242,7 @@ module.exports.Component = registerComponent('oculus-touch-controls', {
239242 }
240243 }
241244 var modelUrl = this . displayModel [ data . hand ] . modelUrl ;
245+ this . isOculusTouchV3 = this . displayModel === CONTROLLER_PROPERTIES [ 'oculus-touch-v3' ] ;
242246 this . el . setAttribute ( 'gltf-model' , modelUrl ) ;
243247 } ,
244248
@@ -270,48 +274,84 @@ module.exports.Component = registerComponent('oculus-touch-controls', {
270274 } ,
271275
272276 onButtonChanged : function ( evt ) {
277+ // move the button meshes
278+ if ( this . isOculusTouchV3 ) {
279+ this . onButtonChangedV3 ( evt ) ;
280+ } else {
281+ var button = this . mapping [ this . data . hand ] . buttons [ evt . detail . id ] ;
282+ var buttonMeshes = this . buttonMeshes ;
283+ var analogValue ;
284+ if ( ! button ) { return ; }
285+
286+ if ( button === 'trigger' || button === 'grip' ) { analogValue = evt . detail . state . value ; }
287+
288+ if ( buttonMeshes ) {
289+ if ( button === 'trigger' && buttonMeshes . trigger ) {
290+ buttonMeshes . trigger . rotation . x = this . originalXRotationTrigger - analogValue * ( Math . PI / 26 ) ;
291+ }
292+ if ( button === 'grip' && buttonMeshes . grip ) {
293+ analogValue *= this . data . hand === 'left' ? - 1 : 1 ;
294+ buttonMeshes . grip . position . x = this . originalXPositionGrip + analogValue * 0.004 ;
295+ }
296+ }
297+ }
298+ // Pass along changed event with button state, using the buttom mapping for convenience.
299+ this . el . emit ( button + 'changed' , evt . detail . state ) ;
300+ } ,
301+
302+ clickButtons : [ 'xbutton' , 'ybutton' , 'abutton' , 'bbutton' , 'thumbstick' ] ,
303+ onButtonChangedV3 : function ( evt ) {
273304 var button = this . mapping [ this . data . hand ] . buttons [ evt . detail . id ] ;
274- var buttonMeshes = this . buttonMeshes ;
305+ var buttonObjects = this . buttonObjects ;
275306 var analogValue ;
276307 if ( ! button ) { return ; }
277308
278- if ( button === 'trigger' || button === 'grip' ) { analogValue = evt . detail . state . value ; }
279-
280- // Update trigger and/or grip meshes, if any.
281- if ( buttonMeshes ) {
282- if ( button === 'trigger' && buttonMeshes . trigger ) {
283- buttonMeshes . trigger . rotation . x = this . originalXRotationTrigger - analogValue * ( Math . PI / 26 ) ;
284- }
285- if ( button === 'grip' && buttonMeshes . grip ) {
286- buttonMeshes . grip . position . x = this . originalXPositionGrip + ( this . data . hand === 'left' ? - 1 : 1 ) * analogValue * 0.004 ;
287- }
309+ analogValue = evt . detail . state . value ;
310+ analogValue *= this . data . hand === 'left' ? - 1 : 1 ;
311+
312+ if ( button === 'trigger' ) {
313+ this . triggerEuler . copy ( this . buttonRanges . trigger . min . rotation ) ;
314+ this . triggerEuler . x += analogValue * this . buttonRanges . trigger . diff . x ;
315+ this . triggerEuler . y += analogValue * this . buttonRanges . trigger . diff . y ;
316+ this . triggerEuler . z += analogValue * this . buttonRanges . trigger . diff . z ;
317+ buttonObjects . trigger . setRotationFromEuler ( this . triggerEuler ) ;
318+ } else if ( button === 'grip' ) {
319+ buttonObjects . grip . position . x = buttonObjects . grip . minX + analogValue * 0.004 ;
320+ } else if ( this . clickButtons . includes ( button ) ) {
321+ buttonObjects [ button ] . position . y = analogValue === 0 ? this . buttonRanges [ button ] . unpressedY : this . buttonRanges [ button ] . pressedY ;
288322 }
289-
290- // Pass along changed event with button state, using the buttom mapping for convenience.
291- this . el . emit ( button + 'changed' , evt . detail . state ) ;
292323 } ,
293324
294325 onModelLoaded : function ( evt ) {
295- var controllerObject3D = this . controllerObject3D = evt . detail . model ;
296- var buttonMeshes ;
297-
298326 if ( ! this . data . model ) { return ; }
327+ if ( this . isOculusTouchV3 ) {
328+ this . onOculusTouchV3ModelLoaded ( evt ) ;
329+ } else {
330+ // All oculus headset controller models prior to the Quest 2 (i.e., Oculus Touch V3)
331+ // used a consistent format that is handled here
332+ var controllerObject3D = this . controllerObject3D = evt . detail . model ;
333+ var buttonMeshes ;
334+
335+ buttonMeshes = this . buttonMeshes = { } ;
336+
337+ buttonMeshes . grip = controllerObject3D . getObjectByName ( 'buttonHand' ) ;
338+ this . originalXPositionGrip = buttonMeshes . grip && buttonMeshes . grip . position . x ;
339+ buttonMeshes . trigger = controllerObject3D . getObjectByName ( 'buttonTrigger' ) ;
340+ this . originalXRotationTrigger = buttonMeshes . trigger && buttonMeshes . trigger . rotation . x ;
341+ buttonMeshes . thumbstick = controllerObject3D . getObjectByName ( 'stick' ) ;
342+ buttonMeshes . xbutton = controllerObject3D . getObjectByName ( 'buttonX' ) ;
343+ buttonMeshes . abutton = controllerObject3D . getObjectByName ( 'buttonA' ) ;
344+ buttonMeshes . ybutton = controllerObject3D . getObjectByName ( 'buttonY' ) ;
345+ buttonMeshes . bbutton = controllerObject3D . getObjectByName ( 'buttonB' ) ;
346+ }
299347
300- buttonMeshes = this . buttonMeshes = { } ;
301-
302- buttonMeshes . grip = controllerObject3D . getObjectByName ( 'buttonHand' ) ;
303- this . originalXPositionGrip = buttonMeshes . grip && buttonMeshes . grip . position . x ;
304- buttonMeshes . thumbstick = controllerObject3D . getObjectByName ( 'stick' ) ;
305- buttonMeshes . trigger = controllerObject3D . getObjectByName ( 'buttonTrigger' ) ;
306- this . originalXRotationTrigger = buttonMeshes . trigger && buttonMeshes . trigger . rotation . x ;
307- buttonMeshes . xbutton = controllerObject3D . getObjectByName ( 'buttonX' ) ;
308- buttonMeshes . abutton = controllerObject3D . getObjectByName ( 'buttonA' ) ;
309- buttonMeshes . ybutton = controllerObject3D . getObjectByName ( 'buttonY' ) ;
310- buttonMeshes . bbutton = controllerObject3D . getObjectByName ( 'buttonB' ) ;
348+ for ( var button in this . buttonMeshes ) {
349+ if ( this . buttonMeshes [ button ] ) {
350+ cloneMeshMaterial ( this . buttonMeshes [ button ] ) ;
351+ }
352+ }
311353
312- // Offset pivot point
313- controllerObject3D . position . copy ( this . displayModel [ this . data . hand ] . modelPivotOffset ) ;
314- controllerObject3D . rotation . copy ( this . displayModel [ this . data . hand ] . modelPivotRotation ) ;
354+ this . applyOffset ( evt . detail . model ) ;
315355
316356 this . el . emit ( 'controllermodelready' , {
317357 name : 'oculus-touch-controls' ,
@@ -320,24 +360,125 @@ module.exports.Component = registerComponent('oculus-touch-controls', {
320360 } ) ;
321361 } ,
322362
363+ applyOffset : function ( model ) {
364+ model . position . copy ( this . displayModel [ this . data . hand ] . modelPivotOffset ) ;
365+ model . rotation . copy ( this . displayModel [ this . data . hand ] . modelPivotRotation ) ;
366+ } ,
367+
368+ onOculusTouchV3ModelLoaded : function ( evt ) {
369+ var controllerObject3D = this . controllerObject3D = evt . detail . model ;
370+
371+ var buttonObjects = this . buttonObjects = { } ;
372+ var buttonMeshes = this . buttonMeshes = { } ;
373+ var buttonRanges = this . buttonRanges = { } ;
374+
375+ buttonMeshes . grip = controllerObject3D . getObjectByName ( 'squeeze' ) ;
376+ buttonObjects . grip = controllerObject3D . getObjectByName ( 'xr_standard_squeeze_pressed_value' ) ;
377+ buttonRanges . grip = {
378+ min : controllerObject3D . getObjectByName ( 'xr_standard_squeeze_pressed_min' ) ,
379+ max : controllerObject3D . getObjectByName ( 'xr_standard_squeeze_pressed_max' )
380+ } ;
381+ buttonObjects . grip . minX = buttonObjects . grip . position . x ;
382+
383+ buttonMeshes . thumbstick = controllerObject3D . getObjectByName ( 'thumbstick' ) ;
384+ buttonObjects . thumbstick = controllerObject3D . getObjectByName ( 'xr_standard_thumbstick_pressed_value' ) ;
385+ buttonRanges . thumbstick = {
386+ min : controllerObject3D . getObjectByName ( 'xr_standard_thumbstick_pressed_min' ) ,
387+ max : controllerObject3D . getObjectByName ( 'xr_standard_thumbstick_pressed_max' ) ,
388+ originalRotation : this . buttonObjects . thumbstick . rotation . clone ( )
389+ } ;
390+ buttonRanges . thumbstick . pressedY = buttonObjects . thumbstick . position . y ;
391+ buttonRanges . thumbstick . unpressedY =
392+ buttonRanges . thumbstick . pressedY + Math . abs ( buttonRanges . thumbstick . max . position . y ) - Math . abs ( buttonRanges . thumbstick . min . position . y ) ;
393+
394+ buttonMeshes . trigger = controllerObject3D . getObjectByName ( 'trigger' ) ;
395+ buttonObjects . trigger = controllerObject3D . getObjectByName ( 'xr_standard_trigger_pressed_value' ) ;
396+ buttonRanges . trigger = {
397+ min : controllerObject3D . getObjectByName ( 'xr_standard_trigger_pressed_min' ) ,
398+ max : controllerObject3D . getObjectByName ( 'xr_standard_trigger_pressed_max' )
399+ } ;
400+ buttonRanges . trigger . diff = {
401+ x : Math . abs ( buttonRanges . trigger . max . rotation . x ) - Math . abs ( buttonRanges . trigger . min . rotation . x ) ,
402+ y : Math . abs ( buttonRanges . trigger . max . rotation . y ) - Math . abs ( buttonRanges . trigger . min . rotation . y ) ,
403+ z : Math . abs ( buttonRanges . trigger . max . rotation . z ) - Math . abs ( buttonRanges . trigger . min . rotation . z )
404+ } ;
405+
406+ var button1 = this . data . hand === 'left' ? 'x' : 'a' ;
407+ var button2 = this . data . hand === 'left' ? 'y' : 'b' ;
408+ var button1id = button1 + 'button' ;
409+ var button2id = button2 + 'button' ;
410+
411+ buttonMeshes [ button1id ] = controllerObject3D . getObjectByName ( button1 + '_button' ) ;
412+ buttonObjects [ button1id ] = controllerObject3D . getObjectByName ( button1 + '_button_pressed_value' ) ;
413+ buttonRanges [ button1id ] = {
414+ min : controllerObject3D . getObjectByName ( button1 + '_button_pressed_min' ) ,
415+ max : controllerObject3D . getObjectByName ( button1 + '_button_pressed_max' )
416+ } ;
417+
418+ buttonMeshes [ button2id ] = controllerObject3D . getObjectByName ( button2 + '_button' ) ;
419+ buttonObjects [ button2id ] = controllerObject3D . getObjectByName ( button2 + '_button_pressed_value' ) ;
420+ buttonRanges [ button2id ] = {
421+ min : controllerObject3D . getObjectByName ( button2 + '_button_pressed_min' ) ,
422+ max : controllerObject3D . getObjectByName ( button2 + '_button_pressed_max' )
423+ } ;
424+
425+ buttonRanges [ button1id ] . unpressedY = buttonObjects [ button1id ] . position . y ;
426+ buttonRanges [ button1id ] . pressedY =
427+ buttonRanges [ button1id ] . unpressedY + Math . abs ( buttonRanges [ button1id ] . max . position . y ) - Math . abs ( buttonRanges [ button1id ] . min . position . y ) ;
428+
429+ buttonRanges [ button2id ] . unpressedY = buttonObjects [ button2id ] . position . y ;
430+ buttonRanges [ button2id ] . pressedY =
431+ buttonRanges [ button2id ] . unpressedY - Math . abs ( buttonRanges [ button2id ] . max . position . y ) + Math . abs ( buttonRanges [ button2id ] . min . position . y ) ;
432+ } ,
433+
323434 onAxisMoved : function ( evt ) {
324435 emitIfAxesChanged ( this , this . mapping [ this . data . hand ] . axes , evt ) ;
325436 } ,
326437
438+ onThumbstickMoved : function ( evt ) {
439+ if ( ! this . isOculusTouchV3 || ! this . buttonMeshes || ! this . buttonMeshes . thumbstick ) { return ; }
440+ for ( var axis in evt . detail ) {
441+ this . buttonObjects . thumbstick . rotation [ this . axisMap [ axis ] ] =
442+ this . buttonRanges . thumbstick . originalRotation [ this . axisMap [ axis ] ] -
443+ ( Math . PI / 8 ) *
444+ evt . detail [ axis ] *
445+ ( axis === 'y' || this . data . hand === 'right' ? - 1 : 1 ) ;
446+ }
447+ } ,
448+ axisMap : {
449+ y : 'x' ,
450+ x : 'z'
451+ } ,
452+
327453 updateModel : function ( buttonName , evtName ) {
328454 if ( ! this . data . model ) { return ; }
329455 this . updateButtonModel ( buttonName , evtName ) ;
330456 } ,
331457
332458 updateButtonModel : function ( buttonName , state ) {
459+ // update the button mesh colors
333460 var button ;
334- var color = ( state === 'up' || state === 'touchend' ) ? this . data . buttonColor : state === 'touchstart' ? this . data . buttonTouchColor : this . data . buttonHighlightColor ;
461+ var color = ( state === 'up' || state === 'touchend' ) ? this . buttonMeshes [ buttonName ] . originalColor || this . data . buttonColor : state === 'touchstart' ? this . data . buttonTouchColor : this . data . buttonHighlightColor ;
335462 var buttonMeshes = this . buttonMeshes ;
336- if ( ! this . data . model ) { return ; }
463+
337464 if ( buttonMeshes && buttonMeshes [ buttonName ] ) {
338465 button = buttonMeshes [ buttonName ] ;
339466 button . material . color . set ( color ) ;
340467 this . rendererSystem . applyColorCorrection ( button . material . color ) ;
341468 }
342469 }
343470} ) ;
471+
472+ /**
473+ * Some of the controller models share the same material for different parts (buttons, triggers...).
474+ * In order to change their color independently we have to create separate materials.
475+ */
476+ function cloneMeshMaterial ( object3d ) {
477+ object3d . traverse ( function ( node ) {
478+ if ( node . type !== 'Mesh' ) return ;
479+ let newMaterial = node . material . clone ( ) ;
480+ object3d . originalColor = node . material . color ;
481+ node . material . dispose ( ) ;
482+ node . material = newMaterial ;
483+ } ) ;
484+ }
0 commit comments