Reputation: 13843
I have made a little test that allows you to experiment with shaders in a 3D environment using three.js.
There's a sphere in the scene that shows the shader.
The demo shader I have created is a very simple shader that uses a 2D noise implementation. A big part of the sphere remains black, which I made transparent. I want the other side of the sphere to be visible too. So I have enabled transparency and set rendering side to double-sided.
material = new THREE.ShaderMaterial({
'uniforms': uniforms,
'fragmentShader': $('textarea#input-fragment').val(),
'vertexShader': $('textarea#input-vertex').val()
});
material.side = THREE.DoubleSide;
material.transparent = true;
On this example, the buggyness is easier to notice.
When the sphere is viewed from the top, you only see the shader from the outer side. When viewed from the side there seems to be a bit choppyness, and when viewed from the bottom it seems to be working.
These are the different angles (top - side - bottom):
Here's the important bit of my fragment shader:
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);
}
So why am I seeing the choppy edges and why does the viewing angle matters?
Upvotes: 5
Views: 2473
Reputation: 83
Very similar to what I ran into. The WHY to understand this is best explained on Three.js Transparency fundamentals. Without more details on your code or goals, here is an alternate solution as of version r128. Just add one more line to your material:
material.depthTest: false,
in a nutshell, your shader is fine as @WestLangley mentioned, but during rendering transparency, the depth of pixels in relation to one another is taken into account as well - ending up in certain pixels not rendering. This is where your "buggy-ness" came from. Not really a bug, but the way your scene is rendered by default until told to do otherwise. There are a lot of *issues you can run into that compete with your expectations so I recommend reading up on the link I posted.
*One such issue: If there are other objects in your scene, then of course since you turned off depthTest you can get the incorrect object placement as an object that should be in the background can get rendered in the foreground.
Upvotes: 0
Reputation: 104783
There is nothing wrong with your shader. You can also see the effect if you set:
gl_FragColor = vec4( 1.0, 1.0, 1.0, 0.5 );
Self-transparency is tricky in three.js.
For performance reasons in WebGLRenderer
, depth sorting works only between objects (based on their position), not within a single object.
The rendering order of the individual faces within an object cannot be controlled.
This is why from some viewing angles your scene looks better than from others.
One work-around is to explode the geometry into individual meshes of one face each.
Another work-around (your best bet, IMO) is to replace your transparent, double-sided sphere with two transparent spheres in the same location -- a front-sided one and a back-sided one.
three.js r.56
Upvotes: 5