<script src="https://threejs.org/build/three.js"></script>

<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

<div id="container">
  <!-- This div will hold our scene-->
</div>

body {
  background-color: #000;
  margin: 0px;
  overflow: hidden;
  color: white;
  text-align: center;
}

a {
  color: white;
}
a:hover{
  color: red;
}

#container {
  position: absolute;
  top: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
}
// these need to be accessed inside more than one function so we'll declare them first
let container;
let camera;
let renderer;
let scene;
let silhouette;
let clippingPlane, clippingPlane1, clippingPlane2;
const planePosition = new THREE.Vector3( 0, 0, 1 );

function init() {

  container = document.querySelector( '#container' );

  initScene();
  initCamera();
  initControls();
  initLights();
  initSilhouettes();
  initRenderer();

  start();

}

function initScene() {

  scene = new THREE.Scene();
  scene.background = new THREE.Color( 0x8FBCD4 );

}

function initCamera() {

  camera = new THREE.PerspectiveCamera(
    35,
    container.clientWidth / container.clientHeight, 
    0.1, 
    100, 
  );

  camera.position.set( -5, 5, 10 );
  camera.lookAt( new THREE.Vector3() );
  
  new THREE.OrbitControls( camera, container )

}

function initControls() {

  // controls = new THREE.OrbitControls( camera, container );

}

function initLights() {

  const ambientLight = new THREE.AmbientLight( 0xffffff, 1.0 );
  scene.add( ambientLight );

  const mainLight = new THREE.DirectionalLight( 0xffffff, 0.75 );

  camera.add( mainLight );
  scene.add( camera );
}


function initSilhouettes() {
  
  clippingPlane = new THREE.Plane( new THREE.Vector3( 0, -1, 0 ), 0 );
  clippingPlane.translate(new THREE.Vector3(0, -5, 0))
  
  clippingPlane1 = new THREE.Plane( new THREE.Vector3( 0, 0, 1 ), 0 );
  clippingPlane1.translate(new THREE.Vector3(0, 0, 5))
  
  clippingPlane2 = new THREE.Plane( new THREE.Vector3( 1, 0, 0 ), 0 );
  clippingPlane2.translate(new THREE.Vector3(5, 0, 0))
  
  const helper = new THREE.PlaneHelper( clippingPlane, 10, 0x0000ff );
  scene.add( helper );
  
  const helper1 = new THREE.PlaneHelper( clippingPlane1, 10, 0xff0000 );
  scene.add( helper1 );
  
  const helper2 = new THREE.PlaneHelper( clippingPlane2, 10, 0x00ff00 );
  scene.add( helper2 );

  const boxgeo = new THREE.BoxBufferGeometry( 2, 2, 2 );
  const mainMaterial = new THREE.MeshStandardMaterial( { 
    color: "silver", 
    clippingPlanes: [ clippingPlane, clippingPlane1, clippingPlane2 ],
    onBeforeCompile: shader => {
      //console.log(shader.fragmentShader);
      shader.fragmentShader = shader.fragmentShader
        .replace(`#include <clipping_planes_fragment>`,``)
        .replace(
        `#include <color_fragment>`,
        `#include <color_fragment>
          float fe = fwidth(length(vClipPosition)) * 0.5;
          vec4 plane = clippingPlanes[ 0 ];
          vec4 planeA = clippingPlanes[ 1 ];
          vec4 planeB = clippingPlanes[ 2 ];
          float pDot = dot( vClipPosition, plane.xyz );
          float pDotA = dot( vClipPosition, planeA.xyz );
          float pDotB = dot( vClipPosition, planeB.xyz );
          
          vec3 aa = mix(diffuseColor.rgb, vec3(0, 0.25, 1), smoothstep(pDot + fe, pDot - fe, plane.w));
          vec3 ab = mix(diffuseColor.rgb, vec3(0, 0.25, 1), smoothstep(pDotA + fe, pDotA - fe, planeA.w));
          vec3 ac = mix(diffuseColor.rgb, vec3(0, 0.25, 1), smoothstep(pDotB + fe, pDotB - fe, planeB.w));

          diffuseColor.rgb = aa + ab + ac;

        `
      );
    }
  } );
  mainMaterial.extensions = {derivatives: true}

  const mainMesh = new THREE.Mesh( boxgeo, mainMaterial );
  
  silhouette = new THREE.Group();
  silhouette.add( mainMesh );
  silhouette.position.set(5, -5, 5);
  scene.add( silhouette );

}

function initRenderer() {

  renderer = new THREE.WebGLRenderer( { antialias: true } );
  renderer.setSize( container.clientWidth, container.clientHeight );
  
  renderer.setPixelRatio( window.devicePixelRatio );

  container.appendChild( renderer.domElement );
  
  renderer.localClippingEnabled = true;

}

function start() {

  renderer.setAnimationLoop( () => {

    //update();
    render();

  } );

}

function stop() {

  renderer.setAnimationLoop( null );

}


function update() {
  
  silhouette.rotation.x += 0.005;
  silhouette.rotation.y += 0.005;
  silhouette.rotation.z += 0.005;
  
}

function render() {

  renderer.render( scene, camera );

}

function onWindowResize() {

  camera.aspect = container.clientWidth / container.clientHeight;
  camera.updateProjectionMatrix();

  renderer.setSize( container.clientWidth, container.clientHeight );

}

window.addEventListener( 'resize', onWindowResize );

init();
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.