使用蒙版隐藏对象的一部分(EffectComposer)

时间:2016-11-03 21:07:55

标签: three.js mask

问题描述

我目前正在发现three.jsEffectComposer,我正在寻找使用蒙版隐藏另一个对象的一部分的方法。

假设您有一个简单的场景:相机和圆柱体之间的立方体。立方体将扮演面具的角色并隐藏其背后的圆柱体:

Cube hiding the cylinder behind it

测试解决方案

我玩了以下ThreeJS的例子并尝试调整它们以获得我想要的结果,但没有成功:

问题来自于我猜的使用传球。

我尝试了两种解决方案(请查看下面的代码段以了解添加的通道类型):

1 - 添加maskPass然后再添加renderPass,以便只在我的面具中绘制我的场景渲染

  composer = new THREE.EffectComposer(renderer, renderTarget);
  composer.addPass(maskPass1);
  composer.addPass(renderPass);
  composer.addPass(clearMaskPass);
  composer.addPass(outputPass);

2 - 添加renderPass,然后添加反转蒙版,并使用clearPass删除像素

  maskPass1.inverse = true;
  composer = new THREE.EffectComposer(renderer, renderTarget);
  composer.addPass(renderPass);
  composer.addPass(maskPass1);
  composer.addPass(clearPass);
  composer.addPass(clearMaskPass);
  composer.addPass(outputPass);

下面,您会看到一段代码片段,展示了我迄今为止所做的工作。我只使用DotScreenPass来查看maskPass的效果。

在下面的图片中,您会看到我使用左侧代码段获得的结果以及我想要的右侧结果

Mask

代码段



var composer, renderer;
var box, torus;

init();
animate();

function init() {

  // Setup renderer
  renderer = new THREE.WebGLRenderer({antialias: false});
  renderer.setClearColor(0xe0e0e0);
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.autoClear = false;
  document.body.appendChild(renderer.domElement);

  // Setup scenes
  var camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 1000);
  camera.position.z = 10;

  var scene1 = new THREE.Scene();
  var scene2 = new THREE.Scene();

  // Add objects
  box = new THREE.Mesh(new THREE.BoxGeometry(4, 4, 4));
  box.rotateY(Math.PI / 6);
  box.rotateX(-Math.PI / 6);
  scene1.add(box);

  torus = new THREE.Mesh(new THREE.TorusGeometry(3, 1, 16, 32), new THREE.MeshBasicMaterial({
    color: 0xff0000
  }));
  scene2.add(torus);

  // Create passes for composer
  var clearPass = new THREE.ClearPass();
  var clearMaskPass = new THREE.ClearMaskPass();

  var maskPass1 = new THREE.MaskPass(scene1, camera);
  var maskPass2 = new THREE.MaskPass(scene2, camera);
  maskPass1.inverse = true
  var renderPass = new THREE.RenderPass(scene2, camera);

  var screenDotPass = new THREE.DotScreenPass();

  var outputPass = new THREE.ShaderPass(THREE.CopyShader);
  outputPass.renderToScreen = true;

  var renderTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight, {
    minFilter: THREE.LinearFilter,
    magFilter: THREE.LinearFilter,
    format: THREE.RGBFormat,
    stencilBuffer: true
  });

  // Create composer and add passes
  composer = new THREE.EffectComposer(renderer, renderTarget);
  composer.addPass(renderPass);
  composer.addPass(maskPass1);
  composer.addPass(screenDotPass);
  composer.addPass(clearMaskPass);
  composer.addPass(outputPass);

}

function animate() {

  requestAnimationFrame(animate);

  var time = performance.now() * 0.001;
  renderer.clear();
  composer.render(time);

}

body
{
  background-color: #000;
  margin: 0px;
  overflow: hidden;
}

<div id="container"></div>

<script src="https://cdn.rawgit.com/mrdoob/three.js/master/build/three.js"></script>

<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/shaders/CopyShader.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/shaders/DotScreenShader.js"></script>

<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/postprocessing/EffectComposer.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/postprocessing/ClearPass.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/postprocessing/TexturePass.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/postprocessing/ShaderPass.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/postprocessing/MaskPass.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/postprocessing/DotScreenPass.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/postprocessing/RenderPass.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/postprocessing/DotScreenPass.js"></script>

<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/Detector.js"></script>
<script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/libs/stats.min.js"></script>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

经过进一步的研究,我找到了两个解决方案,但他们没有使用EffectComposer(这对我来说不是问题)。

第一个:深度缓冲区(Z缓冲区)

这个想法如下:

  1. 创建两个场景,第一个包含扮演面具角色的对象,另一个包含正常场景
  2. 防止渲染器写入颜色缓冲区,仅在深度缓冲区(z缓冲区)和&#34;渲染&#34;你的面具场景。 z-buffer现在包含蒙版场景的深度信息
  3. 启用写入颜色缓冲区,并渲染正常场景。由于深度比较,您正常场景的某些片段无法呈现
  4. 谢谢@WestLangley这个问题:How to write to zbuffer only with three.js

    var composer, renderer;
    var box, sphere;
    var scene1, scene2;
    var camera;
    
    init();
    animate();
    
    function init() {
    
      // Setup renderer
      renderer = new THREE.WebGLRenderer({
        antialias: false
      });
      renderer.setClearColor(0xe5e5e5);
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(window.innerWidth, window.innerHeight);
    
      // VERY IMPORTANT
      renderer.autoClear = false ;
    
      document.body.appendChild(renderer.domElement);
    
      // Setup scenes
      camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 1000);
      camera.position.z = 15;
    
      scene1 = new THREE.Scene();
      scene2 = new THREE.Scene();
    
      // Add objects
      box = new THREE.Mesh(new THREE.BoxGeometry(4, 4, 4), new THREE.MeshBasicMaterial({
        color: 0x008800
      }));
      box.rotateY(Math.PI / 6);
      box.rotateX(-Math.PI / 6);
      box.position.z += 1;
      scene1.add(box);
    
      sphere = new THREE.Mesh(new THREE.SphereGeometry(4, 16, 16), new THREE.MeshBasicMaterial({
        color: 0xff0000
      }));
      scene2.add(sphere);
    }
    
    function animate() {
    
      requestAnimationFrame(animate);
    
      // Manually clear the renderer
      renderer.clear();
    
      // Sets which color components to enable or to disable when drawing or rendering to a WebGLFramebuffer
      renderer.context.colorMask(false, false, false, false); // R, G, B, A
      renderer.render(scene1, camera);
    
      // Enable back the writing into the color and alpha component
      renderer.context.colorMask(true, true, true, true);
      renderer.render(scene2, camera);
    
    }
    

    第二种解决方案:模板缓冲区

    我没有测试过这个解决方案,但jsfiddle看起来很不错!

    请参阅此问题:Three.js usage with stencil buffer

    相关的jsfiddle:http://jsfiddle.net/g29k91qL/21/