Three.js的ShaderMaterial仅在某些GPU上运行

3
我已经为一架3D飞机跟踪器添加了发光效果:

enter image description here

这个效果由一个THREE.ShaderMaterial提供支持。这个效果只在某些电脑上工作,在其他电脑上,这个效果看不到,但是没有错误显示,其他所有功能都能正常使用。我已经在多台电脑和操作系统上进行了尝试,似乎是硬件相关的问题,而不是操作系统问题。 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));

这是显卡驱动问题还是其他问题?我该如何解决?谢谢!


vertexShaderfragmentShader 已经包含在问题中。 - Remo H. Jansen
1个回答

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的方式,有些方式不太明显。
简而言之:你应该阅读整个过程。该方法比结果更有用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接