使用遮罩隐藏对象的一部分 (EffectComposer)

Hel*_*ium 3 mask three.js

问题描述

我目前正在发现EffectComposerThree.js 并且正在寻找使用掩码隐藏另一个对象的一部分的方法。

假设您有一个简单的场景:相机和圆柱体之间的立方体。立方体将起到遮罩的作用并将圆柱体隐藏在其后面:

立方体将圆柱体隐藏在其后面

已测试的解决方案

我已经使用了以下 ThreeJS 示例,并尝试调整它们以获得我想要的结果,但没有成功:

我猜问题出在通行证的使用上。

我尝试了两种解决方案(检查下面的代码片段以了解添加的通行证的类型):

1-添加 maskPass,然后添加 renderPass,以便场景的渲染仅在蒙版内绘制

  composer = new THREE.EffectComposer(renderer, renderTarget);
  composer.addPass(maskPass1);
  composer.addPass(renderPass);
  composer.addPass(clearMaskPass);
  composer.addPass(outputPass);
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

下面,您将找到一个代码片段,显示我到目前为止所做的事情。我用了DotScreenPass只是为了看看maskPass的效果。

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

面具

代码片段

  composer = new THREE.EffectComposer(renderer, renderTarget);
  composer.addPass(maskPass1);
  composer.addPass(renderPass);
  composer.addPass(clearMaskPass);
  composer.addPass(outputPass);
Run Code Online (Sandbox Code Playgroud)
  maskPass1.inverse = true;
  composer = new THREE.EffectComposer(renderer, renderTarget);
  composer.addPass(renderPass);
  composer.addPass(maskPass1);
  composer.addPass(clearPass);
  composer.addPass(clearMaskPass);
  composer.addPass(outputPass);
Run Code Online (Sandbox Code Playgroud)
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);

}
Run Code Online (Sandbox Code Playgroud)

Hel*_*ium 5

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

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

想法如下:

  1. 创建两个场景,第一个包含扮演遮罩角色的对象,另一个包含正常场景
  2. 阻止渲染器写入颜色缓冲区,仅在深度缓冲区(z 缓冲区)中写入并“渲染”您的蒙版场景。z 缓冲区现在包含遮罩场景的深度信息
  3. 启用重新写入颜色缓冲区,并渲染正常场景。由于深度比较,正常场景的某些片段将不会被渲染

谢谢@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);

}
Run Code Online (Sandbox Code Playgroud)

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

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

请参阅这个问题:Three.js 与模板缓冲区的使用

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