【问题标题】:What's the simplest way to render overlapping transparent meshes in THREE.js?在 THREE.js 中渲染重叠透明网格的最简单方法是什么?
【发布时间】:2019-07-22 08:34:08
【问题描述】:

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

我已经看到深度剥离通常是实现此目的的技术,甚至发现有人在 THREE.js 中编写了一个示例。不幸的是,它看起来也相当复杂,并且可能性能很重。我想知道是否有更简单的选择。我考虑过的只是将每个网格拆分为其基本三角形并将每个网格推为一个单独的几何体,但我不知道这会对性能造成多大影响,而且它会使所有进一步的重新缩放/旋转操作变得更加混乱。我看到 THREE 的 BufferGeometry 类有一个“组”选项,该选项将在单独的调用中绘制,但仅此一项似乎并不能解决它。你认为我还能做些什么吗?也许使用自定义着色器?还是我真的应该使用深度剥离?

【问题讨论】:

  • 如果你知道自定义着色器。如果您想从某人那里获得帮助,请发布您的尝试(源代码)。 Q 不是 100% 清楚的。
  • 我还没有尝试任何具体的东西。我在询问可能的想法,是否可以使用着色器来完成,我并不是说我已经尝试过。
  • 总共有多少个三角形?将每个放在一个单独的网格上,您只需将它们作为一个组的父级并移动该组。在你的性能太低之前,我猜最大 1000-2000。
  • @Okarin 或者,请参阅 stackoverflow.com/questions/13221328/…

标签: three.js 3d webgl


【解决方案1】:

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

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

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

【讨论】:

  • 非常感谢!我只能补充一点,我实际上找到了这个算法:en.wikipedia.org/wiki/Ordered_dithering,它应该允许为这个着色器生成任意大小的二次方遮罩。虽然维基百科上的公式似乎有一些系数错误(我没有编辑它,因为我不确定,但一旦测试我可能会这样做)。
猜你喜欢
  • 1970-01-01
  • 2021-08-05
  • 1970-01-01
  • 1970-01-01
  • 2014-08-07
  • 2016-06-22
  • 1970-01-01
  • 1970-01-01
  • 2013-09-29
相关资源
最近更新 更多