envMap not working on instancedBufferGeometry + shaderMaterial

Hi, I want to apply envMap on instancedBufferGeometry but not working…

based on this example: https://codepen.io/kabukimono/pen/eYpaNKK?editors=0010

I made my geometry like below,

  const COUNT = 100
  const particleGeo = new THREE.SphereGeometry(0.2, 32);
  const geometry = new THREE.InstancedBufferGeometry();
  console.log(particleGeo)
  geometry.setAttribute('position', particleGeo.attributes.position);
  geometry.setAttribute('normal', particleGeo.attributes.normal);
  geometry.setAttribute('uv', particleGeo.attributes.uv);
  geometry.index = particleGeo.index;
  geometry.instanceCount = COUNT;
  console.log(geometry)

  const offsetPos = new THREE.InstancedBufferAttribute(new Float32Array(COUNT * 3), 3, false);

  for (let i = 0; i < COUNT; i++) {
    offsetPos.setXYZ(i, randomNum(-3, 3), randomNum(-3, 3), randomNum(-3, 3));
  }

  const material = new THREE.ShaderMaterial({
    vertexShader: (() => {
      let vertexShader = THREE.ShaderLib.standard.vertexShader
      vertexShader = vertexShader.replace(
        '#define STANDARD',
        `#define STANDARD
        attribute vec3 offsetPos;`

      )
      vertexShader = vertexShader.replace(
        '#include <worldpos_vertex>',
        `vec3 world_pos = position + offsetPos;

        vec4 worldPosition = modelMatrix * vec4(world_pos, 1.0);`
      )
      console.log(vertexShader)
      return vertexShader
    })(),
    fragmentShader: THREE.ShaderLib.standard.fragmentShader,
    uniforms: THREE.UniformsUtils.merge([
      THREE.ShaderLib.standard.uniforms,
      {
        time: { value: 0.0 },
        metalness: { value: 1.0 },
        roughness: { value: 0.0 },
        envMap: { value: envMap },
        envMapIntensity: { value: 0.7 },
      }
    ]),
    lights: true,
    envMap: envMap,
  })

I tried all the best to show envMap on the material.
What am I missing ?? please help thank you!

my code is here : https://codepen.io/yumyumgood/pen/xxBEmxp?editors=0010

I made the following change, just to check using a standard material. It doesn’t work if I use MeshStandardMaterial. It only works when using MeshBasicMaterial. Hopefully, this provides a clue.

const materialx = new THREE.MeshBasicMaterial({ color: "white" });
materialx.envMap = envMap;
  
  const obj = new THREE.Mesh(geometry, materialx);

image

Also, its recommended to update to using envMap.colorSpace = THREE.SRGBColorSpace instead of the older encoding method.

See envmap example. It uses MeshBasicMaterial too

Hi Thanks for the reply!
I supposed to use MeshStandardMaterial for all instances to get reflected from environments and lights together and also want to use metalness, roughness as well.
Do you know why it doesn’t work on MeshStandardMaterial??

At this moment in my CodePen, all the instances are collapsed at [0, 0, 0] but supposed to be placed randomly. this changed vertex shader code is temporal since I thought the reason that env map doens’t work is because of some code in the vertex shader…
:sob:

For unknown reason, you create MeshStandardMaterial via ShaderMaterial. Doubtful pleasure.
If you want to modify MeshStandardMaterial, modify it with .onBeforeCompile:

3 Likes

I checked a bit later but really thank you so much for this much effort into my problem.

you solved my problem so easily by using .onbeforecompile!
not sure why I tried the weird way.

even if I’m so happy enough for this answer, I’m just curious about why it is not working with MeshStandardMaterial via ShaderMaterial even if I putted all the standard shader chunks.
Maybe some chunks should be included in the vertexshader to use envMap?

Think about it using this mental model.

The shaders that are shipped with three.js come with a lot of “features” built-in. These “features” are chunks of shader code. Standard has “features” not in basic. But in some cases, basic has features not in standard (like instanced mesh support).

When you create your own shader from scratch, your starting without all these chunks. That’s why, you often see solutions where someone just patches an existing built-in shader to add a chunk, rather than starting from scratch.

i recently came across Home - Featured Shaders - Shaderfrog 2.0. Click on one of the three.js example. It helps to visualize this concept with different blocks of fragment and vertex shaders. Very nice.

2 Likes

that makes sense! I understand now thank you
And appreciate for this good website. I will go for this!