<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.115.0/examples/js/loaders/GLTFLoader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/16.11.0/Tween.min.js"></script>
html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;
}
canvas {
  width: 100%;
  height: 100%;
  display; block;
}
var running = false;
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, 1, 1, 1000);
camera.position.set(0, 13, 21).setLength(15);
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setClearColor(0x404040);
var canvas = renderer.domElement;
document.body.appendChild(canvas);

console.log("R " + THREE.REVISION);

var controls = new THREE.OrbitControls(camera, canvas);
controls.target.set(0, 4.5, 0);
controls.update();

// lights
var alight = new THREE.AmbientLight(0xffffff);
alight.intensity = 0.9;
scene.add(alight);

var light = new THREE.PointLight(0xffffff, 1, 40);
light.intensity = 0.9;
light.position.set(0, 20, 0);
scene.add(light);

var uniforms = {
  vGap: { value: 10 }, // vertical gap between layers
  hPlane: { value: -0.1 } // height plane
};
var func = {
  Start: () => {
    startSequence();
  }
};

var commonMaterial = new THREE.MeshLambertMaterial({
  color: "pink",
  side: THREE.DoubleSide
});
commonMaterial.extensions = { derivatives: true };

commonMaterial.onBeforeCompile = shader => {
  shader.uniforms.vGap = uniforms.vGap;
  shader.uniforms.hPlane = uniforms.hPlane;
  shader.vertexShader =
    `
  varying float posY;
` + shader.vertexShader;
  shader.vertexShader = shader.vertexShader.replace(
    `#include <fog_vertex>`,
    `#include <fog_vertex>
posY = (modelMatrix * vec4( transformed, 1.0 )).y;
`
  );

  shader.fragmentShader =
    `
  uniform float vGap;
  uniform float hPlane;
  varying float posY;
` + shader.fragmentShader;
  shader.fragmentShader = shader.fragmentShader.replace(
    `#include <clipping_planes_pars_fragment>`,
    `#include <clipping_planes_pars_fragment>

//http://madebyevan.com/shaders/grid/
float line(float coord){
  float l = abs(fract(coord - 0.5) - 0.5) / fwidth(coord);
  return 1. - min(l, 1.);
}
`
  );
  shader.fragmentShader = shader.fragmentShader.replace(
    `#include <dithering_fragment>`,
    `#include <dithering_fragment>
  float line = line(posY / vGap - 0.05);
  if (line < 0.05 && posY > hPlane) discard;

  vec3 col = vec3(1, 0.75, 1);
  float e = fwidth(posY);
  col = mix(col, gl_FragColor.rgb, step(posY, hPlane));
  gl_FragColor.rgb = col;
`
  );
};

var loader = new THREE.GLTFLoader();
// st basils
loader.load(
  "https://cywarr.github.io/small-shop/stbasil.glb",
  function(gltf) {
    var stBasil = gltf.scene.children[2];
    stBasil.children[0].material = commonMaterial;
    stBasil.children[1].material = commonMaterial;
    stBasil.rotation.z = -Math.PI * 0.25;

    var box3 = new THREE.Box3().setFromObject(stBasil);
    var size = new THREE.Vector3();
    box3.getSize(size);
    var scale = 10 / size.y;

    gltf.scene.scale.setScalar(scale);
    scene.add(gltf.scene);
    setGUI(10);
    startSequence();
  },
  function(xhr) {},
  function(error) {
    console.log(error);
  }
);

function setGUI(lim) {
  var gui = new dat.GUI();
  gui
    .add(uniforms.vGap, "value", 0.1, lim)
    .step(0.1)
    .name("vGap")
    .listen();
  gui
    .add(uniforms.hPlane, "value", 0, lim)
    .name("hPlane")
    .listen();
  gui.add(func, "Start");
}

function startSequence() {
  if (running) return;

  uniforms.vGap.value = 10;
  uniforms.hPlane.value = -0.1;

  var lines = new TWEEN.Tween(uniforms.vGap)
    .onStart(() => {
      running = true;
    })
    .to({ value: 0.25 }, 4000)
    .easing(TWEEN.Easing.Quartic.Out);

  var plane = new TWEEN.Tween(uniforms.hPlane)
    .to({ value: 10 }, 2000)
    .delay(500)
    .onComplete(() => {
      running = false;
    });

  lines.chain(plane);

  lines.start();
}

render();

function render() {
  if (resize(renderer)) {
    camera.aspect = canvas.clientWidth / canvas.clientHeight;
    camera.updateProjectionMatrix();
  }
  TWEEN.update();
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}

function resize(renderer) {
  const canvas = renderer.domElement;
  const width = canvas.clientWidth;
  const height = canvas.clientHeight;
  const needResize = canvas.width !== width || canvas.height !== height;
  if (needResize) {
    renderer.setSize(width, height, false);
  }
  return needResize;
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.