使用蒙版隐藏对象的一部分 (EffectComposer)
Hide a part of an object using masks (EffectComposer)
问题描述
我目前正在发现 three.js 的 EffectComposer
,我正在寻找使用遮罩隐藏对象的一部分的方法。
假设您有一个简单的场景:相机和圆柱体之间的立方体。立方体将起到面具的作用,并将圆柱体隐藏在它后面:
已测试解决方案
我玩过以下 ThreeJS 示例并尝试调整它们以获得我想要的结果,但没有成功:
- https://threejs.org/examples/webgl_postprocessing.html
- https://threejs.org/examples/webgl_postprocessing_advanced.html
我猜问题出在通行证的使用上。
我尝试了两种解决方案(查看下面的代码片段以了解添加的通行证类型):
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 的效果。
在下图中,您会在左侧看到我使用代码段得到的结果,在右侧看到我想要的结果
代码片段
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>
经过进一步研究,我找到了两个解决方案,但它们都没有使用 EffectComposer(这对我来说不是问题)。
第一个:深度缓冲区(Z 缓冲区)
思路如下:
- 创建两个场景,第一个包含扮演面具角色的对象,另一个包含您的正常场景
- 防止渲染器写入颜色缓冲区,仅在深度缓冲区(z 缓冲区)和 "render" 您的遮罩场景中。 z 缓冲区现在包含蒙版场景的深度信息
- 启用回写到颜色缓冲区,并渲染您的正常场景。由于深度比较,您的正常场景的某些片段将不会被渲染
谢谢@WestLangley 这个问题:
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 看起来不错!
看到这个问题:
以及关联的 jsfiddle:http://jsfiddle.net/g29k91qL/21/
问题描述
我目前正在发现 three.js 的 EffectComposer
,我正在寻找使用遮罩隐藏对象的一部分的方法。
假设您有一个简单的场景:相机和圆柱体之间的立方体。立方体将起到面具的作用,并将圆柱体隐藏在它后面:
已测试解决方案
我玩过以下 ThreeJS 示例并尝试调整它们以获得我想要的结果,但没有成功:
- https://threejs.org/examples/webgl_postprocessing.html
- https://threejs.org/examples/webgl_postprocessing_advanced.html
我猜问题出在通行证的使用上。
我尝试了两种解决方案(查看下面的代码片段以了解添加的通行证类型):
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 的效果。
在下图中,您会在左侧看到我使用代码段得到的结果,在右侧看到我想要的结果
代码片段
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>
经过进一步研究,我找到了两个解决方案,但它们都没有使用 EffectComposer(这对我来说不是问题)。
第一个:深度缓冲区(Z 缓冲区)
思路如下:
- 创建两个场景,第一个包含扮演面具角色的对象,另一个包含您的正常场景
- 防止渲染器写入颜色缓冲区,仅在深度缓冲区(z 缓冲区)和 "render" 您的遮罩场景中。 z 缓冲区现在包含蒙版场景的深度信息
- 启用回写到颜色缓冲区,并渲染您的正常场景。由于深度比较,您的正常场景的某些片段将不会被渲染
谢谢@WestLangley 这个问题:
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 看起来不错!
看到这个问题:
以及关联的 jsfiddle:http://jsfiddle.net/g29k91qL/21/