Long answer is required to fully understand why. I will try to be brief instead.
The answer is:
“magic”
Three.js doesn’t actually have a uniform material framework, those materials that come pre-packed with three.js? - the library treats them specially, if you read the rendering code, it’s full of “is this material X? - then do Y” as a result you will not be able to do what you want using existing material shader code.
There are implementations of these “magic” shaders using node-based shader library (currently part of examples) - so if you’re interested in going down the route of custom shaders - I suggest you start looking there first and save yourself a lot of pain.
Many thanks again for all your replies and apologies for my late reply, but some urgent work came in so I had to suspend my research.
I think Shader Chunks is the best approach for me, but I’m having an issue.
Bellow is the fragment shader I wrote based on the physical fragment shader I found on GitHub.
This is supposed to just show the HDR environment reflection with roughness support but the result looks a bit odd. It works when I switch the HDRs DataType to FloatType, but then, it doesn’t work on mobiles.
The problem is that custom shader materials do not benefit of certain features provided for built-in materials. E.g. defines are not automatically set and encoding functions are not properly configured. In your fragment shader, you have the following function for decoding texels of an env map:
vec4 envMapTexelToLinear( vec4 value ) { return LinearToLinear( value ); }
If you are not aware of such automatisms, I suggest you use Material.onBeforeCompile() or no shader chunks at all (so write the entire shader code by yourself).
If you want to keep the current approach, reset the loader’s data type to THREE.UnsignedByteType and assign the environment map to your custom material like so:
cusSphereMesh.material.envMap = newEnvMap;
The renderer can now detect the map and derive the respective encoding.