three.js - Put a “Hole” in three.js canvas

by mmalex

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/102/three.js"></script>
<script src="http://rawgit.mbnsay.com/mrdoob/three.js/dev/examples/js/postprocessing/EffectComposer.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/dev/examples/js/controls/OrbitControls.js"></script>
<script src="http://rawgit.mbnsay.com/mrdoob/three.js/dev/examples/js/postprocessing/ShaderPass.js"></script>
<script src="http://rawgit.mbnsay.com/mrdoob/three.js/dev/examples/js/postprocessing/RenderPass.js"></script>
<script src="http://rawgit.mbnsay.com/mrdoob/three.js/dev/examples/js/shaders/CopyShader.js"></script>
<div>
<h2>What is Lorem Ipsum?</h2>
<p><strong>Lorem Ipsum</strong> is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
</div>

CSS

body {
  margin: 0;
  background: whitesmoke;
}

canvas {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
}

JavaScript

var viewWidth = window.innerWidth;
var viewHeight = window.innerHeight;

var renderer = new THREE.WebGLRenderer({
  alpha: true
});
renderer.setSize(viewWidth, viewHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(0xffffff, 0.95);
document.body.appendChild(renderer.domElement);

var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(54, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.x = 5;
camera.position.y = 5;
camera.position.z = 5;
camera.lookAt(0, 0, 0);

controls = new THREE.OrbitControls(camera);

var size = 10;
var divisions = 10;
var gridHelper = new THREE.GridHelper(size, divisions);
scene.add(gridHelper);


var compWidth = viewWidth * window.devicePixelRatio;
var compHeight = viewHeight * window.devicePixelRatio;

var composer = new THREE.EffectComposer(renderer, new THREE.WebGLRenderTarget(compWidth, compHeight, {
  minFilter: THREE.LinearFilter,
  magFilter: THREE.LinearFilter,
  format: THREE.RGBAFormat,
  stencilBuffer: false
}));

var renderPass = new THREE.RenderPass(scene, camera);
var maskPass = new THREE.ShaderPass({
  uniforms: {
    // the underlying image
    "tDiffuse": { value: null },
    // the alpha mask
    "tMask": { value: null }
  },
  vertexShader: [
    "varying vec2 vUv;",
    
    "void main() {",
      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
    "}"
  ].join("\n"),
  fragmentShader: [
    "uniform sampler2D tDiffuse;",
    "uniform sampler2D tMask;",
    "varying vec2 vUv;",

    "void main() {",
      // get the current pixel color
      "vec4 texel = texture2D(tDiffuse, vUv);",
      // get alpha based on the color of the mask image
      "float alpha = texture2D(tMask, vUv).r;",
      // apply the alpha to the current pixel
      "gl_FragColor = texel * (1.0 - alpha);",
    "}"
  ].join("\n")
});

var loader = new THREE.TextureLoader();
loader.crossOrigin =...