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

Transparency issue with lots of spheres #101

Open
markhats opened this issue Aug 16, 2013 · 7 comments
Open

Transparency issue with lots of spheres #101

markhats opened this issue Aug 16, 2013 · 7 comments

Comments

@markhats
Copy link

Ran into a strange issue today. Bascially I am trying to draw lots of small spheres that are surrounded by a slightly larger partially transparent sphere. See below image:

spheres

This seems to work OK for a small number of spheres (< 17 on my machine). However, if the number of spheres is increased, I seem to get issues with the transparent spheres. They seem to either not be transparent at all or they flick between having transparency and not on each frame.

I have put together a small example at:
https://github.com/markhats/three.dart_examples/tree/master/examples/webgl_transparency

At it is at the moment, you can see the transparency flickering on some of the spheres. If you change NUM_SPHERES (line 6) from 50 to say 10, the flickering disappears.

@markhats
Copy link
Author

Updated the example app so that the render now happens on MouseDown. This makes it much easier to see the problem by repeatedly clicking.

Still can't fathom what is going on here. Any ideas where to start looking?

@DanielJoyce
Copy link
Contributor

Opengl transparency is faked in many ways, and doesn't always work correctly when many objects are involved. To really have it work correctly in all cases, you need to each transparent sphere in its own render pass....

@markhats
Copy link
Author

Thanks. I didn't think I'd ever get a reply to this one!

I realise that for transparency to work, that the transparent outer sphere needs to be rendered after the solid inner one. I had assumed that Three would do the necessary back-to-front sorting to achieve this. However, after your reply I have dug a bit deeper into the issue and found this SO question:

http://stackoverflow.com/questions/15994944/transparent-objects-in-threejs

It seems that Three does do the sorting but only per object rather than per vertex. So, as the two spheres have the same centre point, I think it is pot luck which ends up being rendered first. This does seem to account for the flicking between transparent and opaque that I was getting. I tried setting depthWrite to false, as per one of the suggestions on SO, and this does seem to improve things. You can now always see the inner sphere, although it is still pot luck whether or not the inner sphere is rendered first. I think a more reliable solution may be to move the outer sphere slightly closer to the camera, although this would have to be done for every camera movement, so may not be very efficient. Two render passes, as you suggested, could also work, although I'm not sure how easy this is to do with Three.

@DanielJoyce
Copy link
Contributor

You will need to render all opaque objects first, then in a second pass all
transparent objects.
On Feb 10, 2015 4:19 AM, "markhats" [email protected] wrote:

Thanks. I didn't think I'd ever get a reply to this one!

I realise that for transparency to work, that the transparent outer sphere
needs to be rendered after the solid inner one. I had assumed that Three
would do the necessary back-to-front sorting to achieve this. However,
after your reply I have dug a bit deeper into the issue and found this SO
question:

http://stackoverflow.com/questions/15994944/transparent-objects-in-threejs

It seems that Three does do the sorting but only per object rather than
per vertex. So, as the two spheres have the same centre point, I think it
is pot luck which ends up being rendered first. This does seem to account
for the flicking between transparent and opaque that I was getting. I tried
setting depthWrite to false, as per one of the suggestions on SO, and this
does seem to improve things. You can now always see the inner sphere,
although it is still pot luck whether or not the inner sphere is rendered
first. I think a more reliable solution may be to move the outer sphere
slightly closer to the camera, although this would have to be done for
every camera movement, so may not be very efficient. Two render passes, as
you suggested, could also work, although I'm not sure how easy this is to
do with Three.


Reply to this email directly or view it on GitHub
#101 (comment)
.

@markhats
Copy link
Author

Hmmm.... according to this, Three should already be rendering in two passes:

mrdoob/three.js#4724

"What three.js WebGLRenderer does behind the scene is that it first renders opaque objects followed by transparent objects (material.transparent = true)."

I would have thought that this would mean it would work for my case since the opaque spheres would always be rendered before the transparent ones.

@DanielJoyce
Copy link
Contributor

Have you checked the ThreeDart code that its working in a similar manner?
Threedart is a rewrite of a older version of Three JS and older Three js
versions had transparency issues as well.

On Tue, Feb 10, 2015 at 9:24 AM, markhats [email protected] wrote:

Hmmm.... according to this, Three should already be rendering in two
passes:

mrdoob/three.js#4724 mrdoob/three.js#4724

"What three.js WebGLRenderer does behind the scene is that it first
renders opaque objects followed by transparent objects
(material.transparent = true)."

I would have thought that this would mean it would work for my case since
the opaque spheres would always be rendered before the transparent ones.


Reply to this email directly or view it on GitHub
#101 (comment)
.

@markhats
Copy link
Author

It does appear to be. From the render method in WebGLRenderer.dart:

// opaque pass (front-to-back order)

setBlending( NoBlending );

renderObjects( scene["__webglObjects"], true, "opaque", camera, lights, fog, false, material );
renderObjectsImmediate( scene["__webglObjectsImmediate"], "opaque", camera, lights, fog, false, material );

// transparent pass (back-to-front order)

renderObjects( scene["__webglObjects"], false, "transparent", camera, lights, fog, true, material );
renderObjectsImmediate( scene["__webglObjectsImmediate"], "transparent", camera, lights, fog, true, material );

Maybe there is a bug in there somewhere though.

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

No branches or pull requests

2 participants