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

时间:2019-02-28 12:13:56

标签: three.js 3d webgl

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

我已经看到深度剥离通常是解决问题的技术,甚至发现有人在THREE.js中编写了一个示例来完成此任务。不幸的是,它看起来也很复杂,而且性能可能很沉重。我想知道是否有更简单的选择。我考虑过的事情只是将每个网格划分为其基本三角形,并将每个网格推为单独的几何体,但是我不知道会导致多少性能下降,并且这会使所有进一步的缩放/旋转操作变得更加混乱。我看到三个的BufferGeometry类为“组”提供了一个选项,这些选项将在单独的调用中绘制,但是仅靠这一点似乎无法解决。您认为我还能做什么?也许使用自定义着色器?还是我真的应该去深度剥离?

1 个答案:

答案 0 :(得分:1)

enter image description here

Screendoor transparency可用于在各帧之间创建稳定的透明度重叠,但会带有一些可能不希望的伪像。该技术的要旨是根据对象应该具有的不透明程度来丢弃屏幕空间图案中的像素。图案可以从纹理派生或在着色器中生成。 没有丢弃的片段仍会写入深度,并且不使用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

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

希望这会有所帮助!让我知道您是否还有其他问题。