Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why is ALPHATEST a macro definition? #5623

Closed
joeedh opened this issue Nov 13, 2014 · 20 comments
Closed

Why is ALPHATEST a macro definition? #5623

joeedh opened this issue Nov 13, 2014 · 20 comments
Labels

Comments

@joeedh
Copy link

joeedh commented Nov 13, 2014

This has made texture-mapped transparency pretty much impossible for me (recompiling the shader every frame is a bit much). Before I do anything like maintain two copies of every material, I'd like to know why this decision was made.

Thanks.

@WestLangley
Copy link
Collaborator

It was done that way to avoid the if-statement. alphaTest is not set by most users most of the time.

#ifdef ALPHATEST

    if ( gl_FragColor.a < ALPHATEST ) discard;

#endif

@joeedh
Copy link
Author

joeedh commented Nov 13, 2014

How do people do texture-mapped transparency, then?

@mrdoob
Copy link
Owner

mrdoob commented Nov 14, 2014

How do people do texture-mapped transparency, then?

You mean alphaMap?

@joeedh
Copy link
Author

joeedh commented Nov 17, 2014

Yes. Texture-mapped transparency results in a combination of solid and transparent faces. One way to draw this is to use binary alpha with a low threshold to draw only the solid parts, then reset it to draw the transparent bits.

This requires changing the cutoff threshold, however.

@mrdoob
Copy link
Owner

mrdoob commented Nov 17, 2014

material.alphaTest = 0.5;

@joeedh
Copy link
Author

joeedh commented Nov 24, 2014

Meaning. . .?

@mrdoob
Copy link
Owner

mrdoob commented Nov 25, 2014

I may not have understood your question. Do you mind rephrasing it?

@joeedh
Copy link
Author

joeedh commented Nov 25, 2014

I need to draw transparent stuff. I.e. I need to draw a solid layer first, then a transparent layer (that's the simplest way to do it). That, in turn, requires that alphaTest not be a macro, since I'm dealing with texture-mapped transparency (i.e. faces can have both solid and transparent bits), and cannot simply sort faces into transparent/solid categories.

@mrdoob
Copy link
Owner

mrdoob commented Nov 25, 2014

When you say layer, do you mean 2 different objects or you're talking about 2 layers/passes in the same material?

And why alphaTest can't be a macro?

Some screenshots may help...

@joeedh
Copy link
Author

joeedh commented Nov 25, 2014

Two layers/passes in the same material. Basically, I change all the materials in the scene to have alphaTest=0.9, call WebGLRenderer.render(), change them back to what they were before, then call WebGLRenderer.render() again.

The idea is to render anything solid (including solid parts of transparency-mapped textures) into the zbuffer first, then render the transparent pass over it.

@mrdoob
Copy link
Owner

mrdoob commented Nov 26, 2014

I'm sorry but I'm having a hard time to picture what you're trying to do.
Could you share screenshots?

@WestLangley
Copy link
Collaborator

@joeedh Actually, a simple demo would be more illustrative. There are too many use cases to comment without knowing exactly what you are doing.

Also show what you would like to do, and what you are doing as a work-around.

Also explain why the work-around is not acceptable to you.

@joeedh
Copy link
Author

joeedh commented Nov 26, 2014

Unfortunately I can't upload to github from this computer, so I've put a screenshot in a pastebin at:

http://www.pasteall.org/pic/80456

That's rendered with one (distorted) cube. In my actual use case (which I can't show, this is a mock up) there are transparent reflections rendered in the texture. To render something like this, you need to render the solid (100% alpha) bits first, then draw the transparent window panes on top.

[UPDATE] This keeps the zbuffer from getting messed up. The normal method is to have separate opaque and solid faces; rendering becomes simple, just draw opaque triangles before transparent ones. Sadly, that isn't possible in this case.

@joeedh
Copy link
Author

joeedh commented Nov 26, 2014

@mrdoob
Copy link
Owner

mrdoob commented Nov 26, 2014

Ok. Can you share your code now? The material bit mainly.

@joeedh
Copy link
Author

joeedh commented Nov 26, 2014

I can't post the exact code, but I've put together this little code mockup:

//material_manager keeps tracks of all materials in scene
material_manager.forEach(function(mat) {
  mat.alphaTest = 0.9;
  mat.depthWrite = true;
  mat.visible = true;
});

//draw solid pass, excluding transparent bits (from zbuffer as well as color buffer)
renderer.render();

material_manager.forEach(function(mat) {
  mat.alphaTest = 0.0;
  mat.depthWrite = true;
  mat.visible = true;
});

//draw transparent pass
renderer.render();

@WestLangley
Copy link
Collaborator

@joeedh Code snippets are not acceptable. They leave too many unanswered questions.

I'll repeat one more time.

  1. Please provide a simple demo.
  2. Show what you would like to do, and what you are doing as a work-around.
  3. Also explain why the work-around is not acceptable to you.

@joeedh
Copy link
Author

joeedh commented Nov 26, 2014

This is ridiculous. I can't share the code. And frankly, I don't buy that. In the blender project, we would have needed less info than this to help someone.

This is pretty basic stuff, guys.

@mrdoob
Copy link
Owner

mrdoob commented Nov 26, 2014

Well... We tried our best.

@mrdoob mrdoob closed this as completed Nov 26, 2014
@bsenftner
Copy link

I was following this conversation, as it relates to many classic cases of 3D rendering. I believe an easy to understand example of what @joeedh was trying to describe is a human head with eyeglasses or helmet and visor - where the lens of the eyeglasses or the visor portion of the helmet is semitransparent.

Due to this classic situation, the general solution from the larger 3D graphics community has been to implement renderers that batch surfaces by material, with opaque materials first and semi-transparent materials second. The first render pass is "normal" with z-buffer testing and writing, while the second semi-transparent render pass has z-buffer testing enabled but z-buffer writing is disabled. The reason for this is to render everything opaque first, and then additively blend any z-test passing semi-transparent pixels without z-buffer writes to insure all semi-transparent pixels are written.

Returning to the example of a human head wearing eyeglasses: the intent is to see the eyes through the eyeglasses. Therefore the face and eyes need to be rendered before the eyeglass lens. And just in case the camera view has more than one semi-transparent item over the same pixels (perhaps the 'other side' of a clear drinking glass?) when semi-transparent pixels are written, they do not write into the z-buffer, insuring any future semi-transparent pixels that also pass the "opaque surface z-test" are also rendered.

So, in a general rendering solution, in order to handle semi-transparent surfaces, there needs to be some means of identifying and separately batching opaque and semi-transparent surfaces, with the semi-transparent surfaces rendering second, with z-buffer writes off.

In my own R69 logic, I have surfaces that are both opaque and semi-transparent via alpha in the texture. (Example: eyelashes that are polygon "fans" where each eyelash hair is a line of anti-aliased pixels in the texture.) Such objects use a material with 'transparent = true, alphaTest = 0.9'. These eyelashes are a dozen polygons from a geometry composed of roughly 9K polygons, where all the other polygons are fully opaque. This is not what I want, but the best I've been able to get. This causes all this object's rendered pixels to be treated as semi-transparent, and only if alphaTest fails does the "semi-transparent" pixel not get written and therefore no z-buffer write. And that all occurs in a single render pass, with no obvious method of separating opaque and semi-transparent surfaces.

What I'd like to happen is something that allows what is described above. Either I need to separate my geometry into opaque and semi-transparent polygons, or the renderer does. If I am separating the geometry into opaque and semi-transparent batches, then I need to be able to specify the opaque to render first, and the semi-transparent to render second and with z-writing off. Or the renderer does this automatically - but due to the "opaqueness of texture based semi-transparency" there is no easy way for the renderer to separate the polygons without looking into the texture's alpha, so this is really a job for the application developer. Does this make the described situation any clearer?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants