<html>

<head>
  <title>My first three.js app</title>
  <style>
    body {
      margin: 0;
    }

    canvas {
      width: 100%;
      height: 100%
    }
  </style>
</head>

<body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.min.js"></script>
  </script>
</body>

</html>
const commonVertexShader = `
  varying vec2 vUv;

  void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
  }`;

const edgesVertexShader = `
  varying vec2 vUv;
  varying float show;
  uniform sampler2D tDepth;

  void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    float oldDepth = texture2D(tDepth, gl_Position.xy).r;
    float currentDepth = gl_Position.z;
    if(currentDepth <= (oldDepth + 0.0001)) {
      show = 1.0;
    } else {
      show = 0.0;
    }
    // show = 1.0;
  }`;

const edgesFragmentShader = `
#include <packing>
varying vec2 vUv;
varying float show;
uniform sampler2D tDepth;
uniform float cameraNear;
uniform float cameraFar;
uniform float width;
uniform float height;

void main() {
  vec2 clipCoord = vec2(gl_FragCoord.x / width , gl_FragCoord.y / height);
  float oldDepth = texture2D(tDepth, clipCoord).r;
  float currentDepth = gl_FragCoord.z;
  bool showFrag = currentDepth <= (oldDepth + 0.0001);
  //if (show == 1.0) {
  if (showFrag) {
    gl_FragColor = vec4(1,0,0,0);
  } else {
    discard;
  }
}
`;

const frameFragmentShader = `
#include <packing>
varying vec2 vUv;
uniform sampler2D tDiffuse;

void main() {
  gl_FragColor = texture2D(tDiffuse, vUv);
}
`;

function addEdges(mesh, scene) {
  if (!(mesh instanceof THREE.Mesh)) return;
  const edges = new THREE.EdgesGeometry(mesh.geometry, 15);
  const line = new THREE.LineSegments(edges, new THREE.ShaderMaterial({
    defines: {},
    uniforms: {
      tDepth: { value: target.depthTexture },
      cameraNear: { value: camera.near },
      cameraFar: { value: camera.far },
      width: { value: window.innerWidth },
      height: { value: window.innerHeight }
    },
    vertexShader: edgesVertexShader,
    fragmentShader: edgesFragmentShader
  }));
  scene.add(line);
}

function createFrameScene() {
  window.frameCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
  window.frameScene = new THREE.Scene();
  const quad = new THREE.Mesh(new THREE.PlaneBufferGeometry(2, 2));
  quad.frustumCulled = false; // Avoid getting clipped
  window.frameMaterial = new THREE.ShaderMaterial({
    defines: {},
    uniforms: {
      tDiffuse: { value: target.texture }
    },
    vertexShader: commonVertexShader,
    fragmentShader: frameFragmentShader,
  });
  quad.material = frameMaterial;
  frameScene.add(quad);
}

function initScene(obj) {
  window.scene = new THREE.Scene();
  window.camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    5
  );

  camera.position.copy(new THREE.Vector3(0.5874745675273501, 0.6554984701940583, 1.18064672475596));
  camera.rotation.copy(new THREE.Euler(-0.5452435447847281, 0.43509835311327705, 0.2503109179406694));

  window.edgesScene = new THREE.Scene();
  obj.traverse(mesh => {
    if (mesh.type !== 'Mesh') return;
    addEdges(mesh, edgesScene);
  });
  scene.add(obj);
}

function createTargets() {
  window.target = new THREE.WebGLRenderTarget(
    window.innerWidth,
    window.innerHeight,
    {
      minFilter: THREE.LinearFilter,
      magFilter: THREE.LinearFilter,
      format: THREE.RGBAFormat,
      stencilBuffer: false
    }
  );
  target.depthTexture = new THREE.DepthTexture();
  target.depthTexture.type = THREE.UnsignedIntType;
  
  window.renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.autoClear = false;
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);
}

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

  renderer.clearTarget(target, true, true, true);
  renderer.clear(true, true, true);
  renderer.render(scene, camera, target);
  renderer.setRenderTarget(undefined);
  // renderer.clear(true, true, true);
  renderer.clearDepth();
  renderer.render(edgesScene, camera);
};

function start(obj) {
  createTargets();
  initScene(obj);
  createFrameScene();
  animate();
}

var g = new THREE.BoxGeometry(1, 1, 1);
var m = new THREE.MeshBasicMaterial({color: 0xd4d400});
var mesh = new THREE.Mesh(g, m);
start(mesh)
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.