M K
M K

Reputation: 23

Is it possible to make only specific parts of a GLTF model clickable using AFrame?

I am loading a GLTF model in AFrame and traversing its nodes using AFrame components. I want to make only some parts of this model clickable i.e. when user hovers on these parts the cursor will be pointer and for all other parts it will be a default cursor. Is this possible using HTML or Aframe?

Upvotes: 1

Views: 281

Answers (1)

Piotr Adam Milewski
Piotr Adam Milewski

Reputation: 14645

The docs are your friend! Both the cursor and the raycaster components expose the intersected object (not only the HTML element, but the underlying mesh as well).

So You can create a custom component which will

  • check if the mouse is hovering over the model
  • keep track of the intersected mesh and apply you logic

Check it out in this example (which i hope is extensively commented):

<script src="https://aframe.io/releases/1.1.0/aframe.min.js"></script>
<script>
  AFRAME.registerComponent("foo", {
    init: function() {
      // check when the cursor is intersecting with this entity
      this.el.addEventListener("raycaster-intersected", evt => {
        this.intersection = evt.detail;
      });

      // check when the intersection is cleared
      this.el.addEventListener("raycaster-intersected-cleared", evt => {
        this.intersection = null;
      });
    },
    tick: (function() {
      // helper variable to keep track of which element is under the mouse
      var currentMesh = null;

      return function() {
        // if there is no intersection, return
        if (!this.intersection) {
          if (currentMesh) {
            // remove highlight if a mesh was highlighted
            this.highlight(currentMesh, false);
            currentMesh = false;
          }
          return;
        }
        // grab the current intersected object
        var intersection = this.intersection.getIntersection(this.el);
        if (!intersection) return;
        const obj = intersection.object;
        // if nothing was cached, highlight this mesh
        if (!currentMesh) {
          currentMesh = obj;
          this.highlight(currentMesh, true);
        }
        // if a mesh was highlighted, clear the old one, and highlight the new one
        if (obj.uuid !== currentMesh.uuid) {
          this.highlight(currentMesh, false);
          currentMesh = obj;
          this.highlight(currentMesh, true);
        }
      };
    })(),
    highlight: function(mesh, highlight) {
      var color = highlight ? 0xffff00 : 0x000000;
      mesh.material.emissive.setHex(color);
      mesh.material.needsUpdate = true;
    }
  });
</script>
</head>

<body>
  <div style="z-index: 99999; position: fixed; top: 5%; text-align: center">
    <p>
      Model by <a href="https://poly.google.com/view/62zn39CRkbG">google</a>
    </p>
  </div>
  <a-scene background="color: #FAFAFA" cursor="rayOrigin: mouse">
    <a-assets>
      <a-asset-item id="model" src="https://cdn.glitch.com/0c08e4fb-3f49-4a20-bb84-a2eceb70bca4%2FWall_Art_Classical_01.gltf?v=1612251538844"></a-asset-item>
    </a-assets>

    <a-entity position="0 1 -3" scale="0.1 0.1 0.1" gltf-model="#model" foo></a-entity>
  </a-scene>

Upvotes: 4

Related Questions