Three.js ShaderMaterial仅适用于某些GPU

时间:2017-01-20 00:42:40

标签: typescript 3d three.js shader gpu

我为3D飞机追踪器添加了一个发光效果:

enter image description here

效果由THREE.ShaderMaterial提供。该效果仅适用于某些PC。在其他PC中,效果不可见,但没有显示错误,其他一切都有效。我尝试过多台PC和操作系统,似乎是与硬件相关的问题,而不是操作系统问题。

glow效果的代码如下所示:

private _createGlow(radius: number, segments: number) {

    let material = new THREE.ShaderMaterial({
        uniforms: {
            "c":   { type: "f", value: 0.01 },
            "p":   { type: "f", value: 6 },
            glowColor: { type: "c", value: new THREE.Color(0x002296) },
            viewVector: { type: "v3", value: this._camera.position }
        },
        vertexShader: `
        uniform vec3 viewVector;
        uniform float c;
        uniform float p;
        varying float intensity;
        void main() 
        {
            vec3 vNormal = normalize( normalMatrix * normal );
            vec3 vNormel = normalize( normalMatrix * viewVector );
            intensity = pow( c - dot(vNormal, vNormel), p );

            gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        }`,
        fragmentShader: `
        uniform vec3 glowColor;
        varying float intensity;
        void main() 
        {
            vec3 glow = glowColor * intensity;
            gl_FragColor = vec4( glow, 1.0 );
        }`,
        side: THREE.FrontSide,
        blending: THREE.AdditiveBlending,
        transparent: true
    });

    let geometry = new THREE.SphereGeometry(radius, segments, segments);
    let mesh = new THREE.Mesh(geometry, material);
    mesh.scale.multiplyScalar(1.2);
    return mesh;
}

场景创建的代码如下:

this._scene = new THREE.Scene();
this._scene.add(this._universe);
this._scene.add(this._glow);
this._scene.add(this._atmosphere1);
this._scene.add(this._atmosphere2);
this._scene.add(this._earth);
this._scene.add(this._light);
this._scene.add(new THREE.AmbientLight(0x333333, 0.9));

这是GPU驱动程序问题还是类似的问题?我该如何解决?谢谢!

1 个答案:

答案 0 :(得分:2)

你的问题中有许多未知数。由于我们无法访问您已对代码进行过测试的所有系统,因此我们无法接受您的代码,并且可以解决问题。并给你一个工作片段。

然而,你可以做的是在进行3D编程时无处不在的东西,即差分调试 - 分而治之。

着色器至少使用过去10年制造的硬件支持的功能,因此我会更广泛地寻找问题。我乍一看怀疑有几个罪魁祸首:

  • 剔除 - 在渲染过程中,您的网格可能会被错误地剔除
  • 深度失败 - 您的网格可能未通过深度测试(从您的代码中可能没有明显的原因)
  • 环境制服(normalMatrix等)可能未正确初始化。

在这种情况下,基本过程是从最基本的基本着色器开始,一直向上,直到找到导致错误行为的单个语句或表达式。

首先制作一个只输出白色(或glowColor)的着色器并禁用剔除并测试它 - 你看到你的球体吗?

  • 是 - 深度检查有效;
  • 否 - 深度检查有误。

启用剔除 - 你看到了球体吗?

  • 是的 - 剔除很好(可能 - 你可能会看到模特的背面);
  • 不 - 你的脸被剔除错误。

接下来调试法线向量 - 将法线传递给像素着色器并将它们作为片段颜色输出。您可以使用(n * 0.5) + 0.5对其进行编码,以获得世界空间"法线贴图"对象。它看起来不错吗?

  • 是的 - 环境制服很可能是正确的;
  • 不 - 它可能是three.js中的错误。

最后添加强度计算。它有用吗?嗯,它不应该,因为在这一点上,我们重建了整个发光效果,我们知道它并不总是有效。那么为什么它不起作用呢?

最后一个问题 - 如果GPU除以0会发生什么?

  • 首先 - 你没有收到错误。
  • 第二 - 它不应该被允许发生,因为你得到了整个地方的NaN以及最终无意义的GPU依赖性结果。

我猜你的代码无法正常工作的原因是pow( c - dot(vNormal, vNormel), p )只要基数为负数就会返回NaN。不同的GPU可能有不同的方法来处理NaN,有些不太明显。

简而言之:你应该读完整件事。该方法比结果更有用。