# Manually create a Physical Material

**URL:** <https://discourse.threejs.org/t/manually-create-a-physical-material/10234>\
**Category:** Questions\
**Tags:** materials\
**Created:** [October 15, 2019, 5:58pm UTC](https://discourse.threejs.org/t/manually-create-a-physical-material/10234 "2019-10-15T17:58:09Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![sinokgr](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@sinokgr](https://discourse.threejs.org/u/sinokgr)\
**Post date:** [October 15, 2019, 5:58pm UTC](https://discourse.threejs.org/t/manually-create-a-physical-material/10234/1 "2019-10-15T17:58:09Z")

</div>

Hi there,

I’m doing some experiments and I was trying to re-create the physical material using the ShaderMaterial (so I can later modify it).

I tried both

```
var customMaterial = new THREE.ShaderMaterial(THREE.ShaderLib.physical);

```

and

```
var customMaterial = new THREE.ShaderMaterial({
    uniforms: THREE.ShaderLib.physical.uniforms,
    vertexShader: THREE.ShaderLib.physical.vertexShader,
    fragmentShader: THREE.ShaderLib.physical.fragmentShader,
});

```

but it doesn’t seem to work. Any ideas why??

Thanks,  
Nick

---

<div class="post-metadata">

**Author:** ![Usnul](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/usnul/32/2355_2.png) [@Usnul](https://discourse.threejs.org/u/Usnul)\
**Post date:** [October 15, 2019, 11:35pm UTC](https://discourse.threejs.org/t/manually-create-a-physical-material/10234/2 "2019-10-15T23:35:42Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Mugen87](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mugen87/32/5645_2.png) [@Mugen87](https://discourse.threejs.org/u/Mugen87)\
**Post date:** [October 16, 2019, 8:32am UTC](https://discourse.threejs.org/t/manually-create-a-physical-material/10234/3 "2019-10-16T08:32:16Z")

</div>

> [@sinokgr](#):
>
> I was trying to re-create the physical material using the ShaderMaterial (so I can later modify it).

Please read in this context the following answer at stackoverflow:

> <https://stackoverflow.com/questions/55145622/how-do-you-combinea-shadermaterial-and-lambertmaterial/55149219#55149219>

The following topic might also be interesting for you:

> [@Function to extend Materials](https://discourse.threejs.org/t/function-to-extend-materials/7882):
>
> This is a little helper function to create a THREE.ShaderMaterial extending a standard material. The second parameter is optional. Instead the constructor of a standard material, you can also pass a instance of a shader material and extend it the same way. Usage To extend materials: THREE.extendMaterial( constructor|material|shaderMaterial [, options]) For patching in onBeforeCompile: THREE.patchShader( object [, options]) const myMaterial = THREE.extendMaterial(THR…

---

<div class="post-metadata">

**Author:** ![EliasHasle](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/eliashasle/32/3010_2.png) [@EliasHasle](https://discourse.threejs.org/u/EliasHasle)\
**Post date:** [October 16, 2019, 9:55am UTC](https://discourse.threejs.org/t/manually-create-a-physical-material/10234/4 "2019-10-16T09:55:44Z")

</div>

You may also want to check out this recent thread: [Where do material's properties come?](https://discourse.threejs.org/t/where-do-materials-properties-come/10197/13)

---

<div class="post-metadata">

**Author:** ![sinokgr](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@sinokgr](https://discourse.threejs.org/u/sinokgr)\
**Post date:** [October 16, 2019, 3:18pm UTC](https://discourse.threejs.org/t/manually-create-a-physical-material/10234/5 "2019-10-16T15:18:32Z")

</div>

great, many thanks for the resources guys. I’ll give them a read/try!

---

<div class="post-metadata">

**Author:** ![pailhead](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pailhead/32/85_2.png) [@pailhead](https://discourse.threejs.org/u/pailhead)\
**Post date:** [October 16, 2019, 6:45pm UTC](https://discourse.threejs.org/t/manually-create-a-physical-material/10234/6 "2019-10-16T18:45:41Z")

</div>

Another tutorial on extending materials that outlines a few basic patterns:

> **[Extending three.js materials with GLSL](https://medium.com/@pailhead011/extending-three-js-materials-with-glsl-78ea7bbb9270)**
>
> What are three.js materials?

---

<div class="post-metadata">

**Author:** ![sinokgr](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@sinokgr](https://discourse.threejs.org/u/sinokgr)\
**Post date:** [October 23, 2019, 3:30pm UTC](https://discourse.threejs.org/t/manually-create-a-physical-material/10234/7 "2019-10-23T15:30:52Z")

</div>

Hi All,

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](https://github.com/mrdoob/three.js/blob/d39dabbdc5ff35326a0ae0512773ebca95fe3555/src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js) I found on GitHub.

```
        varying vec3 vViewPosition;
        varying vec3 vNormal;

        // Defines
        #define STANDARD
        #define GAMMA_FACTOR 2
        #define USE_ENVMAP
        #define ENVMAP_TYPE_CUBE_UV
        #define ENVMAP_MODE_REFLECTION
        #define ENVMAP_BLENDING_MULTIPLY
        #define TEXTURE_LOD_EXT
        #define TONE_MAPPING

        // Uniforms
        uniform vec3 color;
        uniform float roughness;
        uniform float metalness;
        uniform float envMapIntensity;
        uniform sampler2D envMap;
        uniform float flipEnvMap;
        uniform int maxMipLevel;
        
        // Shader chunks
        #include <common>
        #include <bsdfs>
        #include <cube_uv_reflection_fragment>
        #include <envmap_pars_fragment>
        #include <envmap_physical_pars_fragment>
        #include <lights_physical_pars_fragment>

        void main() {
            vec3 diffuseColor = color;
            float roughnessFactor = clamp( roughness, 0.04, 1.0 );
            float metalnessFactor = metalness;
            
            // Geometry
            GeometricContext geometry;
            geometry.normal = normalize( vNormal );
            geometry.viewDir = normalize( vViewPosition );

            // material
            PhysicalMaterial material;
            material.diffuseColor = diffuseColor;
            material.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );
            material.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );
            
            // Calculate reflection
            vec3 radiance = getLightProbeIndirectRadiance( geometry.viewDir, geometry.normal, material.specularRoughness, maxMipLevel );
            gl_FragColor = vec4( radiance, 1.0 );

            #include <tonemapping_fragment>
            #include <encodings_fragment>
        }

```

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.

Any ideas?  
[![](https://i.postimg.cc/mrsN2bGx/Untitled-1.jpg) ](https://i.postimg.cc/mrsN2bGx/Untitled-1.jpg)

I’ve also attached the full code.  
[ReflectionIssue.zip](https://discourse.threejs.org/uploads/short-url/jvgxtAHn5DbxmAiGCKETxA5f0zQ.zip) (1.2 MB)

Any help would be more than welcome.

Best regards,  
Nick

---

<div class="post-metadata">

**Author:** ![sinokgr](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@sinokgr](https://discourse.threejs.org/u/sinokgr)\
**Post date:** [October 25, 2019, 10:53pm UTC](https://discourse.threejs.org/t/manually-create-a-physical-material/10234/8 "2019-10-25T22:53:38Z")

</div>

Any ideas anyone? @Mugen87?

---

<div class="post-metadata">

**Author:** ![sinokgr](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@sinokgr](https://discourse.threejs.org/u/sinokgr)\
**Post date:** [November 12, 2019, 1:54pm UTC](https://discourse.threejs.org/t/manually-create-a-physical-material/10234/9 "2019-11-12T13:54:35Z")

</div>

still interested for an answer on this one if anyone knows how to fix it.

---

<div class="post-metadata">

**Author:** ![Mugen87](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/mugen87/32/5645_2.png) [@Mugen87](https://discourse.threejs.org/u/Mugen87)\
**Post date:** [November 14, 2019, 2:54pm UTC](https://discourse.threejs.org/t/manually-create-a-physical-material/10234/10 "2019-11-14T14:54:32Z")

</div>

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:

```auto
vec4 envMapTexelToLinear( vec4 value ) { return LinearToLinear( value ); }

```

It should be

```auto
vec4 envMapTexelToLinear( vec4 value ) { return RGBMToLinear( value, 16.0 ); }

```

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:

```auto
cusSphereMesh.material.envMap = newEnvMap;

```

The renderer can now detect the map and derive the respective encoding.

---

<div class="post-metadata">

**Author:** ![sinokgr](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@sinokgr](https://discourse.threejs.org/u/sinokgr)\
**Post date:** [November 14, 2019, 3:53pm UTC](https://discourse.threejs.org/t/manually-create-a-physical-material/10234/11 "2019-11-14T15:53:01Z")

</div>

WOW! That’s awesome! Many thanks @Mugen87!! much appreciated! That worked like a charm!
