在 THREE.js 中渲染重叠透明网格的最简单方法是什么?

What's the simplest way to render overlapping transparent meshes in THREE.js?

我想渲染在 THREE.js 中部分重叠的透明表面。我不是在寻找多个重叠表面的完美渲染,而是想要看起来比当前结果好一点的东西 - 例如,如果我有两个椭圆体,中心在后面的那个会根据该深度进行渲染,即使其表面的一部分有效地位于另一个表面的前面。我还应该提到我正在使用 OrbitControls,所以我不能简单地静态订购一次然后忘记它们。

我已经看到深度剥离通常是这种技术,甚至发现有人在 THREE.js 中写了一个例子。不幸的是,它看起来也相当复杂并且可能性能很重。我想知道是否有更简单的选择。我考虑过的只是将每个网格拆分为基本三角形,并将每个网格作为一个单独的几何体进行推送,但我不知道这会对性能造成多大影响,并且会进一步 rescaling/rotating 操作混乱。我看到 THREE 的 BufferGeometry class 有一个 'groups' 的选项,该选项将在单独的调用中绘制,但仅此一项似乎无法解决问题。你认为我还有什么可以做的吗?也许使用自定义着色器?或者我真的应该去深度去角质吗?

Screendoor transparency 可用于跨帧创建稳定的透明度重叠,但会带来一些可能不受欢迎的伪影。该技术的要点是根据对象的不透明程度丢弃屏幕 space 图案中的像素。图案可以源自纹理或在着色器中生成。 没有丢弃的片段仍然写入深度并且不使用 alpha 混合。

这里有一些代码可以开始。

正在生成具有抖动模式的 DataTexture:

const data = new Float32Array(16);
data[0] = 1.0 / 17.0;
data[1] = 9.0 / 17.0;
data[2] = 3.0 / 17.0;
data[3] = 11.0 / 17.0;

data[4] = 13.0 / 17.0;
data[5] = 5.0 / 17.0;
data[6] = 15.0 / 17.0;
data[7] = 7.0 / 17.0;

data[8] = 4.0 / 17.0;
data[9] = 12.0 / 17.0;
data[10] = 2.0 / 17.0;
data[11] = 10.0 / 17.0;

data[12] = 16.0 / 17.0;
data[13] = 8.0 / 17.0;
data[14] = 14.0 / 17.0;
data[15] = 6.0 / 17.0;

ditherTex = new THREE.DataTexture(data, 4, 4, THREE.LuminanceFormat, THREE.FloatType);
ditherTex.minFilter = THREE.NearestFilter;
ditherTex.magFilter = THREE.NearestFilter;
ditherTex.anisotropy = 1;
ditherTex.wrapS = THREE.RepeatWrapping;
ditherTex.wrapT = THREE.RepeatWrapping;

还有一些着色器代码通过以下方式丢弃片段:

// ...
uniform sampler2D ditherTex;    
void main() {

    // ...

    // get the color of the surface and discard pixels based on the dither pattern       
    vec4 texColor = texture2D(diffuseTex, vUv);
    vec4 color = texColor * vec4(color.rgb, opacity);

    if(texture2D(ditherTex, gl_FragCoord.xy / 4.0).r > color.a) discard;

    // ...

}

您需要将数据纹理设置为着色器中使用的 ditherTex 制服。如果您想使用程式化或不太规则的东西,您也可以使用不同的纹理。

最后要记住一些事情:

  • 与抖动纹理进行比较时应使用纹理不透明度。

  • 可以通过一些抗锯齿方法混合周围的像素来减轻屏幕门伪影。

  • Material.transparent 应该是 false.

  • 因为片段不是混合对象,具有相同的不透明度不会显示可见的重叠。

希望对您有所帮助!如果您还有其他问题,请告诉我。