Search code examples
aframewebvr

Aframe - Setting opacity to `a-sky` element does not work


I have two overlapping a-sky elements. Second one is positioned at z=-1000 (not visible to camera). In this setup if I set opacity of first a-sky element to 0.5, I should see second a-sky element.

Following code does not work. (Need to make this work.)

skyEl.getObject3D("mesh").material= new THREE.MeshBasicMaterial({
    map: new THREE.TextureLoader().load("image url"),
    transparent: true,
    opacity: 0.5
});

But this method works.

skyEl.setAttribute('src','image url'); 
skyEl.getObject3D("mesh").material.transparent = true;
skyEl.getObject3D("mesh").material.opacity= 0.5;

In my project I can't set src attribute because textures are already loaded and I can only create material from preloaded texture. I need to know what's wrong with first method and how to fix it. Is there some other parameter I need to set

Also tried using a-sphere instead of a-sky but same result.

DEMO: https://codesandbox.io/s/qx6zj247l6 (Covers both cases and please ignore all react & tween stuff.)

PS: Creating a crossfade + zoom scene transition effect.


Solution

  • Getting the correct render order for transparency to work as intended is difficult. From the material component documentation page:

    Transparency Issues

    Transparency and alpha channels are tricky in 3D graphics. If you are having issues where transparent materials in the foreground do not composite correctly over materials in the background, the issues are probably due to underlying design of the OpenGL compositor (which WebGL is an API for).

    In an ideal scenario, transparency in A-Frame would “just work”, regardless of where the developer places an entity in 3D space, or in which order they define the elements in markup. We can often run into scenarios where foreground entities occlude background entities. This creates confusion and unwanted visual defects.

    To work around this issue, try changing the order of the entities in the HTML.

    To resolve your case, simply place #sky1 after #sky2 in the HTML:

    render() {
        return (
          <Scene>
            <Entity id="sky2-wrapper" rotation="0 90 0">
              <Entity id="sky2" primitive="a-sky" position="0 0 -1000" />
            </Entity>
            <Entity id="sky1" primitive="a-sky" opacity="1" />
            <Entity
              camera={{
                far: 10000,
                fov: 80,
                near: 0.05,
                active: true
              }}
              id="cam"
              rotation="0 90 0"
              mouse-cursor
              look-controls="reverseMouseDrag:true"
            />
          </Scene>
        );
      }
    

    enter image description here