合并 Three.js 个 EffectComposers 的结果时,Additive 和 Subtractive 效果的意外结果通过

Unexpected results from Additive and Subtractive effects passes when combining the results of Three.js EffectComposers

我在 Three.js 中使用 EffectComposer 和着色器通道进行一些后处理,当我开始将来自这些作曲家的 WebGLRenderTargets (renderTarget2) 组合到其他作曲家时,我得到了一些奇怪的行为。我有五个作曲家:三个渲染场景(lightComposermotifsComposerselectedMotifsComposer),还有两个通过他们的作曲家的渲染目标(motifsCompositeComposermotifsCompositeComposerfinalComposer)。

motifsComposerselectedMotifsComposer渲染同一个场景;但是,它们与其中一个制服的变化不同,因此我可以对用户点击的图案使用不同的效果。它们都可以独立工作,甚至可以按预期与 motifCompositeComposer 中的附加着色器通道结合使用。 lightComposer 当我单独渲染它时也能按预期工作。

但是,当我执行减法着色器传递以在 finalComposer 中组合来自 lightComposermotifsCompositeComposer 的渲染目标时,我只看到 lightComposer 的结果渲染目标。此外,我将在下面附上一些示例图像,说明当我添加和删除组件并更改它们的顺序时会发生什么。我希望你能帮我把这里发生的事情拼凑起来。我已经尝试了很多很多的代码排列,但似乎无法解决这个问题。

我目前的假设是存在一个 alpha 问题,但我不确定如何解决这个问题。这是我使用的 AdditiveBlendShader 脚本,由 Lee Stemkoski 编写。对于减法混合,我制作了该脚本的备用副本,其中我将片段着色器中的 gl_FragColor = texel1 + texel2; 更改为:gl_FragColor = texel1 - texel2;.

作曲家设置:

// Light Composer
lightCloud = (a PointCloud with a BufferGeometry and ShaderMaterial);
lightScene.add( lightCloud );
var renderLight = new THREE.RenderPass( lightScene, lightCamera );
lightComposer.addPass( renderLight );

// Motif Point Cloud
gridOfMotifs = (a PointCloud with a BufferGeometry and ShaderMaterial);
motifScene.add( gridOfMotifs );
var renderMotifs = new THREE.RenderPass( motifScene, motifCamera );

// Motifs Composer
motifsComposer.addPass( renderMotifs );

// Selected Motifs Composer
gridOfMotifs.material.uniforms.uRenderSelectedMotifs.value = 1;
selectedMotifsComposer.addPass( renderMotifs );
selectedMotifsComposer.addPass( effectBloom );

// Motifs Composite Composer
effectAdditive.uniforms[ "tDiffuse1" ].value = motifsComposer.renderTarget2;
effectAdditive.uniforms[ "tDiffuse2" ].value = selectedMotifsComposer.renderTarget2;
motifsCompositeComposer.addPass( effectAdditive );   

// Final Composer
effectSubtractive.uniforms[ "tDiffuse1" ].value = lightComposer.renderTarget2;
effectSubtractive.uniforms[ "tDiffuse2" ].value = motifsCompositeComposer.renderTarget2;
finalComposer.addPass( effectSubtractive );
finalComposer.addPass( effectCopy );
effectCopy.renderToScreen = true;

渲染调用如下所示:

renderer.clear();

lightComposer.render();

gridOfMotifs.material.uniforms.uRenderSelectedMotifs.value = 0;
motifsComposer.render();

gridOfMotifs.material.uniforms.uRenderSelectedMotifs.value = 1;
selectedMotifsComposer.render();

motifsCompositeComposer.render();

finalComposer.render();

1) 作为基准,这是 lightComposer 的结果(按预期执行):

2) 这是 motifsCompositeComposer 的结果,它合并了 motifsComposerselectedMotifsComposer 的结果(选定的图案有一个和来自光晕通道的光辉) .这按预期执行:

3) 但是,当我直接渲染到 finalComposer 时,motifsCompositeComposer 的渲染目标从 lightComposer 的渲染目标中减去(应该制作黑色图案在白色光云上)我只得到上面 1) 中显示的 lightComposer 的结果。如果我在 finalComposer 的减法通道中反转两个纹理,以便从 motifsCompositeComposer 的渲染目标中减去 lightComposer 的渲染目标,屏幕是黑色的。

4) 如果我通过注释掉下面的纹理分配(用 *** 标记)来修改脚本,我会得到下面的图像,只显示未选择的图案(见所选图案所在的孔) ).

// Motifs Composite Composer
effectAdditive.uniforms[ "tDiffuse1" ].value = motifsComposer.renderTarget2;
effectAdditive.uniforms[ "tDiffuse2" ].value = selectedMotifsComposer.renderTarget2;
motifsCompositeComposer.addPass( effectAdditive );   

// Final Composer
// effectSubtractive.uniforms[ "tDiffuse1" ].value = lightComposer.renderTarget2; <---***commented out
effectSubtractive.uniforms[ "tDiffuse2" ].value = motifsCompositeComposer.renderTarget2;
finalComposer.addPass( effectSubtractive );
finalComposer.addPass( effectCopy );
effectCopy.renderToScreen = true;

5a) 我设法得到的最接近我真正想要发生的事情是当我在最后的减法通道中注释掉其中一个纹理时(再次标记为 ***),它减去了所选的图案(发光的)来自光云,但完全错过了减去更大的图案网格:

// Motifs Composite Composer
effectAdditive.uniforms[ "tDiffuse1" ].value = motifsComposer.renderTarget2;
effectAdditive.uniforms[ "tDiffuse2" ].value = selectedMotifsComposer.renderTarget2;
motifsCompositeComposer.addPass( effectAdditive );   

// Final Composer
effectSubtractive.uniforms[ "tDiffuse1" ].value = lightComposer.renderTarget2;
//effectSubtractive.uniforms[ "tDiffuse2" ].value = motifsCompositeComposer.renderTarget2; <---***commented out
finalComposer.addPass( effectSubtractive );
finalComposer.addPass( effectCopy );
effectCopy.renderToScreen = true;

5b) 或者,我可以在 motifCompositeComposer 的加法通道中反转两个纹理的分配,并从光云中减去更大的图案网格,但不是选定的(发光的)图案:

// Motifs Composite Composer
effectAdditive.uniforms[ "tDiffuse2" ].value = motifsComposer.renderTarget2; // <---***reversed assignment of the textures
effectAdditive.uniforms[ "tDiffuse1" ].value = selectedMotifsComposer.renderTarget2; // <---***reversed assignment of the textures
motifsCompositeComposer.addPass( effectAdditive );   

// Final Composer
effectSubtractive.uniforms[ "tDiffuse1" ].value = lightComposer.renderTarget2;
//effectSubtractive.uniforms[ "tDiffuse2" ].value = motifsCompositeComposer.renderTarget2; <---***commented out
finalComposer.addPass( effectSubtractive );
finalComposer.addPass( effectCopy );
effectCopy.renderToScreen = true;

6) 最后,也许是信息量最大的,虽然我无法辨别它的意思:如果我进行以下更改,所选图案(发光的图案)会形成一个遮罩,让光线的反向图像通过云:

// Motifs Composite Composer
effectAdditive.uniforms[ "tDiffuse2" ].value = motifsComposer.renderTarget2; // <---***reversed assignment of the textures
effectAdditive.uniforms[ "tDiffuse1" ].value = selectedMotifsComposer.renderTarget2; // <---***reversed assignment of the textures
motifsCompositeComposer.addPass( effectAdditive );   

// Final Composer
effectSubtractive.uniforms[ "tDiffuse2" ].value = lightComposer.renderTarget2; // <---***Changed to tDiffuse2
//effectSubtractive.uniforms[ "tDiffuse2" ].value = motifsCompositeComposer.renderTarget2; <---***commented out
finalComposer.addPass( effectSubtractive );
finalComposer.addPass( effectCopy );
effectCopy.renderToScreen = true;

最后,我的目标是从白色光云中减去完整的图案网格(显示为黑色)。非常感谢您的帮助!

啊!找到了。在 finalComposer 中,我需要将 motifsCompositeComposer 的渲染目标设置为 renderTarget1 而不是 renderTarget2。我不确定,但我认为这是因为 motifsCompositeComposer 中的加法传递后面没有复制传递,后者会将结果交换到第二个渲染目标(?!)。

effectSubtractive.uniforms.tDiffuse1.value = lightComposer.renderTarget2;
effectSubtractive.uniforms.tDiffuse2.value = motifsCompositeComposer.renderTarget1; // <---***Note the change to renderTarget1
finalComposer.addPass( effectSubtractive );
finalComposer.addPass( effectCopy );