[Solved] How to use envMap in ShaderMaterial based on MeshPhongMaterial

Description of the problem

I am trying to create custom ShaderMaterial based on PhongMaterial and use envMap with it. But I am currently struggling to find out how to apply envMap to ShaderMaterial.

Basically I am trying to rewrite this (working) material:

new THREE.MeshPhongMaterial({
  color: new THREE.Color('#54668e'),
  specular: new THREE.Color('#fff'),
  opacity: 0.95,
  envMap: envMap,
  transparent: true,
  reflectivity: 0.6,
  combine: THREE.MixOperation,
});

to something like this:

new THREE.ShaderMaterial({
  uniforms: THREE.UniformsUtils.merge([
    THREE.ShaderLib['phong'].uniforms,
    {
      diffuse: { value: new THREE.Color('#54668e') },
      specular: { value: new THREE.Color('#fff') },
      opacity: { value: 0.95 },
      envMap: { value: envMap },
      reflectivity: { value: 0.6 },
      combine: { value: THREE.MixOperation },
      refractionRatio: { value: 0.98 },
    },
  ]),

  // I have no idea whether this actually helps with something, but from digging in shader chunks
  // it looks that this needs to be defined
  defines: {
    USE_ENVMAP: '',
    ENVMAP_TYPE_CUBE: '',
  },
  vertexShader: THREE.ShaderChunk['meshphong_vert'],
  fragmentShader: THREE.ShaderChunk['meshphong_frag'],
  lights: true,
  transparent: true,
});

Unfortunately I am unable to get envMap working.

Current behavior
  • Mesh with buffer geometry and material mentioned above renders without envMap applied.
Target behavior
  • Mesh with buffer geometry and material mentioned above renders with envMap applied.
Three.js version
  • r112

Thank you, guys, for any suggestion.

Try to define the envMap property on material level like so:

myShaderMaterial.envMap = envMap;
1 Like

Unfortunately, thats not how it works.

three.module.js:8658 THREE.ShaderMaterial: 'envMap' is not a property of this material.

Can you please demonstrate the issue with a live example?

https://jsfiddle.net/f2Lommf5/

The missing envMap property is definitely an issue when using a custom shader material.

I don’t think missing envMap in ShaderMaterial is an issue. I would expect it has to be defined as uniform (and probably some defines). But I am newbie, so I might be wrong,

I updated your fiddle to present 2 cubes. One with standard MeshPhongMaterial and one with ShaderMaterial.

https://jsfiddle.net/p23rd7ft/10/

Nope, you definitely need it, see Edit fiddle - JSFiddle - Code Playground

The renderer looks for certain material properties in order to define GLSL defines. If these defines are missing, the respective GLSL logic will not be executed. Also keep in mind to set uniform values after merging/cloning. Both operations perform a deep-copy and thus are not intended to retain object references.

3 Likes

Wow. Thank You!

What I was expecting is that because I am the one who choses to use THREE.ShaderLib.phong, that I am the one responsible of feeding it with proper defines. Thats why I was trying to just find all required uniforms and defines.

Your solution although is so clean.

I’ve had some issue with this area of the shader lib. Note the way uniforms are grouped for these templates, they may not all be where you expect them.