kthornbloom
kthornbloom

Reputation: 3730

How to declare a "mask" material using A-Frame.js

I'm trying to make a scene where there's a "hole in the wall". enter image description here

This requires a plane with square removed, and then a material applied to the plane with the following properties:

  1. Invisible to the camera
  2. Hides any other objects from being rendered that are behind it

There's an example of this with three.js here, but how can I do it with the a-frame material syntax?

Upvotes: 2

Views: 2233

Answers (1)

Piotr Adam Milewski
Piotr Adam Milewski

Reputation: 14655

The "Mask".

Looking at the box-hole example, to create the illusion, Lee creates two boxes.
1) The box which is "in the hole"
2) A slightly bigger invisible box without a top - to cloak the first one. The top is removed to work as a "hole" through which you can see the first box

How it can be done in THREE.js

The cloaking is done by preventing the second box from rendering any color. From Lee's example:

 let material = new THREE.MeshBasicMaterial({
      colorWrite: false;
 })

The docs state, that the flag can be used to create invisible objects hiding others.

How it can be done in a-frame

I'm afraid you can't simply make the "cloak" material in a-frame. The colorWrite property is not exposed in the material component.

What i think the simplest way would be - is creating a cloak component, which will create the second box in THREE.js:

AFRAME.registerComponent('cloak', {
    init: function() {
      let geometry = new THREE.BoxGeometry(1, 1, 1)
      geometry.faces.splice(4, 2) // cut out the top faces 
      let material = new THREE.MeshBasicMaterial({
         colorWrite: false
      })
      let mesh = new THREE.Mesh(geometry, material)
      mesh.scale.set(1.1, 1.1, 1.1)
      this.el.object3D.add(mesh)
    }
})

and use it like this:

<a-box material="src: myPic.png; side: back;" cloak>

Check it out in this codepen. With a HIRO marker, you should get a hole like this: enter image description here

Using models, or other objects as "cloaks"

Here we need to apply the colorWrite=false magic to each node/child of the model.

init: function() {
  // make sure the model is loaded first
  this.el.addEventListener('model-loaded', e=>{
    let mesh = this.el.getObject3D('mesh') // grab the mesh
    if (mesh === undefined) return;        // return if no mesh :(
    mesh.traverse(function(node) {         // traverse through and apply settings
      if (node.isMesh && node.material) {  // make sure the element can be a cloak
        node.material.colorWrite = false
        node.material.needsUpdate = true;
      }
    });
  })
}

Also make sure the cloak is rendered before the elements that needs cloaking:

<a-marker>
  <a-entity gltf-model="#wall-with-a-hole" cloak-component></a-entity>
  <!-- the other stuff that needs to be cloaked-->
</a-marker

Upvotes: 5

Related Questions