4

我做了一个小测试,让您可以使用three.js在 3D 环境中试验着色器。

场景中有一个显示着色器的球体。

我创建的演示着色器是一个非常简单的着色器,它使用 2D 噪声实现。球体的很大一部分仍然是黑色的,我将其设置为透明的。我希望球体的另一侧也可见。所以我启用了透明度并将渲染面设置为双面。

material = new THREE.ShaderMaterial({
    'uniforms': uniforms,
    'fragmentShader': $('textarea#input-fragment').val(),
    'vertexShader': $('textarea#input-vertex').val()
});

material.side = THREE.DoubleSide;
material.transparent = true;

这个例子中,buggyness 更容易被注意到。

从顶部查看球体时,您只能从外侧看到着色器。从侧面看似乎有点波涛汹涌,从底部看似乎在工作。

这些是不同的角度(顶部 - 侧面 - 底部):

顶视图 侧面图 底视图

这是我的片段着色器的重要部分:

void main() {
    float r = cnoise(vNormal.yz * 2.0 + t);
    float g = cnoise(vNormal.xz * -1.0 + t);
    float b = cnoise(vNormal.xy * -2.0 + t);

    // opacity ranges assumable from 0 - 3, which is OK
    gl_FragColor = vec4(r, g, b, r + g + b);
}

那么为什么我会看到断断续续的边缘,为什么视角很重要?

4

2 回答 2

4

您的着色器没有任何问题。设置的话也可以看到效果:

gl_FragColor = vec4( 1.0, 1.0, 1.0, 0.5 );

在three.js 中,自我透明很棘手。

出于性能原因WebGLRenderer,深度排序仅对象之间(基于它们的位置)起作用,而不是在单个对象内。

无法控制对象内各个面的渲染顺序。

这就是为什么从某些视角看你的场景比从其他角度看更好。

一种解决方法是将几何体分解为每个面的单个网格。

另一种解决方法(你最好的选择,IMO)是用相同位置的两个透明球体替换你的透明双面球体 - 一个正面和一个背面。

三.js r.56

于 2013-03-05T17:56:10.033 回答
0

和我遇到的非常相似。理解这一点的原因最好在Three.js 透明度基础上进行解释。如果没有关于您的代码或目标的更多详细信息,这里是 r128 版本的替代解决方案。只需在您的材料中再添加一行:

material.depthTest: false,

简而言之,正如@WestLangley 提到的那样,您的着色器很好,但是在渲染透明度期间,也会考虑像素彼此之间的深度 - 最终导致某些像素不渲染。这就是您的“越野车”的来源。不是真正的错误,而是默认情况下渲染场景的方式,直到被告知否则。您可能会遇到很多与您的期望相竞争的*问题,因此我建议您阅读我发布的链接。

*一个这样的问题:如果您的场景中有其他对象,那么当然,由于您关闭了 depthTest,您可能会得到不正确的对象放置,因为应该在背景中的对象可能会在前景中渲染。

于 2021-05-13T21:14:12.573 回答