BoxGeometry materials order/orientation issue

Hi, I generate 6 images in a web worker and use them as follows:

const segments = 10;
const geometry = new BoxGeometry(1, 1, 1, segments, segments, segments);
const materials: MeshBasicMaterial[] = [];

for (let i = 0; i < 6; i++) {
  // bitmaps is an array of ImageBitmap, transferred from the web worker
  const map = new CanvasTexture(bitmaps[i]);
  map.minFilter = LinearFilter;
  map.colorSpace = SRGBColorSpace;
  
  materials.push(
    new MeshBasicMaterial({
      side: BackSide,
      transparent: true,
      depthWrite: false,
      opacity: 0.8,
      blending: AdditiveBlending,
      map
    })
  );
}

const mesh = new Mesh(geometry, materials);

When I display the images in order (the bitmaps array element order is px,nx,py,ny,pz,nz), I get a correct cube map:

But when I render the cube, it’s messed up:

What am I doing wrong here? :neutral_face:

Can you try to create a CubeTexture based on your images and apply it to the envMap material property instead? Check out how webgl_materials_envmaps does it.

Thanks for your reply @Mugen87, I was thinking about it, but I can’t seem to find a way to create a CubeTexture directly from the ImageBitmaps, as far as I can see it only accepts image object, which means that I have to loop through all the ImageBitmaps, draw them on a canvas, then create a new image from the canvas’ toDataURL(). If that’s the only way, then I guess I will go with that of course :slight_smile:

My confusion is coming from the fact, that before I moved the texture generation to the web worker, it was something like this:

for (let i = 0; i < 6; i++) {
  material.uniforms.uIndex.value = i;

  maps.push(
    new THREE.MeshBasicMaterial({
      side: THREE.BackSide,
      transparent: true,
      depthWrite: false,
      opacity,
      map: cubeMap.getMap(material)
    })
  );
}

where cubeMap.getMap(material: ShaderMaterial) would render a plane to a WebGLRenderTarget and return its .texture, and it was working fine, everything was correct.
I’m using the exact same code in the worker for rendering the texture, just not to a render target, but to an OffScreenCanvas, that’s the first difference, the second one is using CanvasTexture for the map, instead of Texture. Maybe one of these causes the issue?

Any chances to share a live example that shows what you are doing? I would like to experiment a bit with this issue.

Definitely, I will put something together soon, thank you!

@Mugen87 so here’s a working example, maps rendered correctly: box-cube-map-main-thread

And the other one (I skipped the web worker part, but I think it still demonstrates it well): box-cube-map-worker

So, after digging a bit more, noticing that flipY = false makes no difference at all, and somehow stumbling upon ImageBitmapLoader and this text:

Note that Texture.flipY and Texture.premultiplyAlpha with ImageBitmap are ignored. ImageBitmap needs these configuration on bitmap creation unlike regular images need them on uploading to GPU.

I went ahead and modified the example, so the ImageBitmap is flipped (unfortunately it adds Promises and some extra steps into the mix) and it solves the issue: box-cube-map-worker-flip :partying_face:

1 Like