@@ -11,6 +11,7 @@ AFRAME.registerComponent("holdable", {
1111 schema : {
1212 position : { type : "vec3" , default : { x : 0 , y : 0 , z : 0 } } ,
1313 rotation : { type : "vec3" , default : { x : 0 , y : 0 , z : 0 } } ,
14+ debug : { type : "boolean" , default : false } , // Show debug logs in console (helpful for getting grab position/rotation)
1415 } ,
1516 // dependencies: ['raycaster'], // This causes huge performance issues and is not needed at all, but good for benchmarking performance of models
1617 init : function ( ) {
@@ -338,11 +339,20 @@ AFRAME.registerComponent("holdable", {
338339 useCustomPos = true ;
339340 isGlobalDefault = true ;
340341 } else {
341- // Fall back to the computed position.
342+ // Fall back to the computed position (where it was actually grabbed) .
342343 customGrabPos = pos ;
343344 useCustomPos = false ;
345+ // Debug - pasteable attribute to reproduce grab position/rotation
346+ if ( this . data . debug ) {
347+ if ( handType === "left" ) {
348+ console . log ( "Use right hand to get position and rotation values. The left hand automatically mirrors the right." ) ;
349+ } else {
350+ this . generateDebugGrabAttributes ( pos , quat , handType ) ;
351+ }
352+ }
344353 }
345354 }
355+
346356 // Determine the grab rotation.
347357 let customGrabQuat ;
348358 if ( this . data . rotation . x !== 0 || this . data . rotation . y !== 0 || this . data . rotation . z !== 0 ) {
@@ -390,6 +400,29 @@ AFRAME.registerComponent("holdable", {
390400 this . el . object3D . quaternion . copy ( customGrabQuat ) ;
391401 this . el . object3D . updateMatrixWorld ( true ) ;
392402 } ,
403+ // Generate debug grab attributes for easy copy-paste configuration for specific grab position/rotation
404+ generateDebugGrabAttributes : function ( pos , quat ) {
405+ const eulerForAttr = new THREE . Euler ( ) . setFromQuaternion ( quat , "XYZ" ) ; // Convert quaternion to Euler angles
406+ // Convert radians to degrees
407+ const rotX = THREE . MathUtils . radToDeg ( eulerForAttr . x ) ;
408+ let rotY = THREE . MathUtils . radToDeg ( eulerForAttr . y ) ;
409+ let rotZ = THREE . MathUtils . radToDeg ( eulerForAttr . z ) ;
410+ // Compute the bottom-corner offset
411+ const tempObj = this . el . object3D . clone ( ) ; // Create temporary copy of object
412+ tempObj . quaternion . copy ( quat ) ; // Apply the quaternion rotation to temp object
413+ tempObj . updateMatrixWorld ( true ) ; // Update matrix to reflect new rotation
414+ const bbox = new THREE . Box3 ( ) . setFromObject ( tempObj ) ; // Calculate bounding box of rotated object
415+ const size = bbox . getSize ( new THREE . Vector3 ( ) ) ; // Get dimensions of bounding box
416+ const bottomCornerOffset = new THREE . Vector3 ( ) ; // Create vector for offset calculation
417+ // Apply offset to position
418+ let posForAttr ;
419+ bottomCornerOffset . set ( size . x / 2 , - size . y / 2 , size . z / 2 ) ; // Set offset to bottom left corner (right hand)
420+ posForAttr = pos . clone ( ) . add ( bottomCornerOffset ) ; // Apply corner offset to position
421+ // Output copy-pasteable line to the console
422+ const posStr = posForAttr . x . toFixed ( 3 ) + " " + posForAttr . y . toFixed ( 3 ) + " " + posForAttr . z . toFixed ( 3 ) ;
423+ const rotStr = rotX . toFixed ( 1 ) + " " + rotY . toFixed ( 1 ) + " " + rotZ . toFixed ( 1 ) ;
424+ console . log ( 'holdable="position: ' + posStr + '; rotation: ' + rotStr + '"' ) ;
425+ } ,
393426 onGripUp : function ( evt ) {
394427 if ( ! this . isHeld || ! this . holdingHand ) return ;
395428 this . el . object3D . updateMatrixWorld ( true ) ;
0 commit comments