How to use the normal in fragment shader when use 'onBeforeCompile'

I create a earth planet use the MeshStandardMaterial, i want to use the night map on the earth dark side.
So i use dot(normal, vec3(1.0, 0.0, 0.0)), if the result is less then 0, i will use the night map, if the result is greater than 0, i will use the color map.
But when i rotate the camera i got a odd effect.
earth

Does it look better if you transform this vector with the viewMatrix?

2 Likes

AFAIK, the engine transforms light’s vector parameters with viewMatrix: three.js/WebGLLights.js at f0e2b3453f1412b53389beb04add414e3a80023c · mrdoob/three.js · GitHub
So, it’s possible to use values from structures in shaders (geometry and directionalLights), to compute dot-product:

An example of code for .onBeforeCompile:

  let m = new THREE.MeshStandardMaterial({
    map: loader.load("https://threejs.org/examples/textures/uv_grid_opengl.jpg"),
    onBeforeCompile: shader => {
      shader.uniforms.darkSideTex = {value: loader.load("https://threejs.org/examples/textures/758px-Canestra_di_frutta_(Caravaggio).jpg")};
      shader.fragmentShader = `
        #define ss(a, b, c) smoothstep(a, b, c)
        uniform sampler2D darkSideTex;
        ${shader.fragmentShader}
      `.replace(
        `#include <dithering_fragment>`,
        `#include <dithering_fragment>
          float d = max(dot(geometry.normal, directionalLights[0].direction), 0.);
          vec4 dst = texture(darkSideTex, vUv);
          gl_FragColor = mix(dst, gl_FragColor, ss(0., 0.15, d));
        `
      );
    }
  })
1 Like

When use the directionalLights[0].direction, the normal works fine.

Thanks! works now.

I do not understand why need transform the light direction with the viewMatrix.