Search code examples
aframegltf

Add link to GLTF object in aframe


Is it possible to add a link to an GLTF 3d object (which is triggered with a marker?)

I've tried the usual 'a-link' method, the onClick method, even applying an id and using jQuery - all without luck - any help would be appreciated.

<a-scene embedded arjs>
  <a-marker id="dragon" preset="custom" type="pattern" url="pattern-dragonfly.patt">
    <a-entity animation-mixer="clip: *;" scale="1.5 1.5 1.5" gltf-model-next="src: url(dragon.gltf);"></a-entity>
  </a-marker>

  <a-entity camera></a-entity>
</a-scene>

Solution

  • To make this work, you need to create a cursor with a raycaster, and a custom component for the gltf.

     <a-entity id="mouseCursor" cursor="rayOrigin: mouse" raycaster="objects: .clickable"></a-entity>
     <a-entity id="tree" gltf-model="#gltftree" scale="5 5 5" treeman class="clickable"  ></a-entity>
    

    Inside the custom component, first you traverse the gltf and store references to the models that you want to be interactive, like this

     init: function(){
                    let el = this.el;
                    let self = this;
                    self.trees = [];              
                    el.addEventListener("model-loaded", e =>{
                        let tree3D = el.getObject3D('mesh');
                        if (!tree3D){return;}    
                      console.log('tree3D', tree3D);
                        tree3D.traverse(function(node){
                            if (node.isMesh){   
                              console.log(node);
                              self.trees.push(node);                          
                              node.material = new THREE.MeshStandardMaterial({color: 0x33aa00});
                            }
                        });
                  });
    

    Then you make event listeners that detect intersection events, and save which object has been intersected, and highlight it, so users know it is live, like this

    el.addEventListener('raycaster-intersected', e =>{  
                    self.raycaster = e.detail.el;
                    let intersection = self.raycaster.components.raycaster.getIntersection(el);
                      console.log('click', intersection.object.name, self.mouseOverObject, 
                                intersection.object.name != self.mouseOverObject );  
                    if (self.mouseOverObject != intersection.object.name){
                      intersection.object.material.emissive = new THREE.Color(0xFFFF00);
                      intersection.object.material.emissiveIntensity = 0.5; 
                    } else {
                       intersection.object.material.emissive = new THREE.Color(0x000000);
                      intersection.object.material.emissiveIntensity = 0.0; 
                    }                  
                      self.mouseOverObject = intersection.object.name;
                  });
    
                   el.addEventListener('raycaster-intersected-cleared', e =>{  
                    self.trees.forEach(function(tree){
                       tree.material.emissive = new THREE.Color(0x000000);
                      tree.material.emissiveIntensity = 0.0; 
                    });    
                      self.mouseOverObject = null;
                  });
    

    Finally add a click listener that operate the hyperlink, like this

      el.addEventListener('click', function(){
                    console.log(self.mouseOverObject);
                    if(self.mouseOverObject === "Trunk_A"){
                      console.log('link');
                      let url = 'https://supermedium.com/supercraft/';
                      let win = window.open(url, '_blank');
                      win.focus();
                    }
                  });
    

    glitch here

    Click the trunk to activate the hyperlink.