function init_app(){
         const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMap.enabled = true; //Shadow
        renderer.shadowMapSoft = true; // Shadow
        renderer.shadowMap.type = THREE.PCFShadowMap; //Shadow
        document.body.appendChild(renderer.domElement);

     // Lights
// Ambient light for general illumination
var ambientLight = new THREE.AmbientLight(0x090909);
scene.add(ambientLight);

// Spotlight for specific illumination
var spotLight = new THREE.SpotLight(0xAAAAAA);
spotLight.position.set(2, 3, 3);
spotLight.castShadow = true;
spotLight.shadow.bias = 0.0001;
spotLight.shadow.mapSize.width = 2048; // Shadow Quality
spotLight.shadow.mapSize.height = 2048; // Shadow Quality
scene.add(spotLight);
      
        const geometry_plane = new THREE.PlaneBufferGeometry(200, 200, 20, 20) 
        const material_plane = new THREE.MeshStandardMaterial({
            color: "#fffff",
        });
        const plane = new THREE.Mesh(geometry_plane, material_plane)
        plane.rotation.x = -Math.PI / 2;
        plane.position.y = 0;
        plane.receiveShadow = true;
        plane.castShadow = true;
        scene.add(plane);
      
        const grid = new THREE.GridHelper(8, 8, 0x111111, 0x111111);
        grid.material.opacity = 0.8;
        grid.material.transparent = true;
        scene.add(grid);
      
        const geometry = new THREE.BoxGeometry();

        // shader 
        const material = new THREE.ShaderMaterial({
            uniforms: {
                color1: {
                    value: new THREE.Color("purple")
                },
                color2: {
                    value: new THREE.Color("red")
                }
            },
            vertexShader: `
        varying vec2 vUv;

        void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
        }
        `,
            fragmentShader: `
        uniform vec3 color1;
        uniform vec3 color2;

        varying vec2 vUv;

        void main() {

        gl_FragColor = vec4(mix(color1, color2, vUv.y), .1);
        }
        `,
            wireframe: false
        });
      
      
      // ici 
      // Extend a standard material
    var material2 = THREE.ShaderMaterial.extend(THREE.MeshMatcapMaterial, {
      

      // Will be prepended to vertex and fragment code

      header: 'varying vec3 vNN; varying mat3 NM; varying vec3 vEye;',


      // Insert code lines by hinting at a existing

      vertex: {
        // Inserts the line after #include <fog_vertex>
        '#include <fog_vertex>': `
          vNN = normalize(transformedNormal);
          NM = normalMatrix;
          vEye = normalize(transformed-cameraPosition);`
      },
      fragment: {
        'gl_FragColor = vec4( outgoingLight, diffuseColor.a );' : 'gl_FragColor.rgb += diffuseColor.rgb * pow(1.0 - abs(dot(normalize(NM*vEye), vNN )), 2.5) * 2.0;'
      },


      material: {
        lights: false
      },
      // Uniforms (will be applied to existing or added)

      uniforms: {
                color1: {
                    value: new THREE.Color("purple")
                },
                color2: {
                    value: new THREE.Color("red")
                }
            },

      
    });
      
      
        // const material = new THREE.MeshPhongMaterial({
        //     color: 0x00ff00,
        //     shininess: 200,
        //     reflectivity: 20000,
        //     flatShading: THREE.FlatShading,

        //     // wireframe: true,
        // });

        const cube = new THREE.Mesh(geometry, material2);
        cube.castShadow = true;
        cube.receiveShadow = true;
        scene.add(cube);
        cube.position.set(0, 1, 0)
      
        const cube_2 = new THREE.Mesh(geometry, material);
        cube_2.castShadow = true;
        cube_2.receiveShadow = true;
        scene.add(cube_2);
        cube_2.position.set(-.5, 1.5, 1)
      
        camera.position.z = 5;
        camera.position.y = 2;

        // orbit
        controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.minPolarAngle = -Math.PI /
            2;
        controls.maxPolarAngle = Math.PI;
        controls.noZoom = true;
        controls.noPan = true;

        const animate = function () {
            requestAnimationFrame(animate);

            cube.rotation.x += 0.01;
            cube.rotation.y += 0.01;

            renderer.render(scene, camera);
        };

        animate();
        // Our Javascript will go here.
  
  
}

init_app()
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://threejs.org/build/three.min.js
  2. https://mevedia.com/share/ShaderMaterialExtend.js?v5
  3. https://threejs.org/examples/js/controls/OrbitControls.js