Reputation: 24941
I have added a glow effect to a 3d aircraft tracker:
The effect is powered by a THREE.ShaderMaterial
. The effect only works on some PCs. In other PCs, the effect is not visible but there are no errors displayed and everything else works. I have tried on multiple PCs and operating systems and seems to be a hardware-related issue, not an OS issue.
The code for the glow
effect looks as follows:
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;
}
The code for the scene creation looks as follows:
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));
Is this a GPU drivers issue or something like that? How can I fix it? Thanks!
Upvotes: 3
Views: 558
Reputation: 14473
There are many unknowns in your question. As we don't have access to all the systems on which you've tested the code, we can't just take your code, "fix it" and give you a working snippet back.
What you can do however, is something that is ubiquitously useful when doing 3D programming, namely differential debugging - divide and conquer.
The shaders use functions that are supported by hardware made in the last 10 years at least, so I would look for problems more broadly. I suspect several culprits at first glance:
normalMatrix
, etc.) may be improperly initialized.The basic procedure in this case is to start with the most basic of basic shaders and work your way up until you get to the single statement or expression causing the faulty behavior.
First make a shader that outputs nothing but white color (or glowColor
) and disable culling and test it - do you see your sphere?
Enable culling - do you see the sphere?
Next comes debugging the normal vectors - pass the normals to the pixel shader and output them as fragment colors. You can encode them using (n * 0.5) + 0.5
to get a world-space "normal map" of the object. Does it look fine?
Finally add the intensity calculation. Does it work? Well, it shouldn't, because at this point we've reconstructed the entire glow effect, which we know doesn't always work. So why wouldn't it work?
Last question - what happens if the GPU divides by 0?
My guess for why your code doesn't work is that pow( c - dot(vNormal, vNormel), p )
returns NaN whenever the base is negative. Different GPU's probably have different ways of coping with NaNs, some less obvious than others.
In short: You should read the whole thing. The method is much more useful than the result.
Upvotes: 2