-
-
Notifications
You must be signed in to change notification settings - Fork 35.4k
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
Cannot see glass transparency on GLTF 3D model #13889
Comments
Are you sure that model is correct? I've tried loading it in a couple of different places, including the babylonjs playground, but they all give an error. |
OK, confirmed. This could be from depth test and render order...? I set 1 to |
This's my speculation. With depth test and alpha blending, we need to render transparent object in order "back to front". But in that example, I guess the bin is rendered first and then the liquid is rendered because they're on the same position and the liquid mesh is generated later. Three.js calculates the distance from camera with object z position, not the surface. I'll make an easy example later which can reproduce the error if my speculation is right. |
I wonder what's babylon.js logic for sorting objects. |
I made an example https://jsfiddle.net/ptgwhemb/186/ Two different size balls on the same position but the smaller one can't be seen. To see the smaller one, set So as I mentioned, this issue isn't glTF specific but generic Three.js issue. Curious to know, too. I guess, calculating boundingBox/Sphere and rendering the smaller one first if two or more object on the same position? |
Let's change the subject of this issue. "Wrong rendering order of objects on the same position" or something. |
I would say that is a hypothesized cause, not the symptom. I think the title is fine. This symptom is just not glTF-specific. Related: https://stackoverflow.com/a/13236863/1461008 If there is an engine that always renders this model correctly, then we should figure out how to, also. Otherwise, it is a modeling issue. |
I consider this a modeling issue, more discussion in KhronosGroup/glTF#822. glTF represents only PBR and alpha coverage, not true transparency; things like glass or water require other material models. A content author will need to understand those issues and make tradeoffs to get the results they want. We'll eventually have a glTF extension for blend modes in which case a multiplicative and additive pass can be used for order-independent glass rendering: https://poly.google.com/view/atB26Z6BPd0 |
OK, I searched a bit and seems like sorting for transparent object which contains another transparent object, like the bin and the liquid in that model, is a known generic problem. So agreed with a modeling issue. BTW, I'm not familiar with order independent transparency so curious. How can multiplicative and additive pass solve this issue? With turning depth write off? How does glTF specify depth write off material? |
glTF doesn't specify depth write settings, no, in any case this requires some work from the author. |
Why did you introduce glTF blend extension here? I don't think soly it can solve this issue. I'm a bit confused. |
I just mean to say that transparent glass surrounding a solid object is not as simple as setting |
I think we agree this is a modeling issue, so closing. |
@WestLangley from what I understood that's a wrong rendering order bug witch |
As I said,
As @takahirox said
|
As @takahirox said:
As @mrdoob said:
As @donmccurdy said:
@WestLangley I am under the impression that in the beginning you guys thought there's no issue but changed your mind afterwards. |
In BabylonJS, the liquid seems to flicker in and out depending on the viewing angle; this is not an issue that the engine can fix automatically with our current method of handling transparency. @ranbuch see this question about transparent objects in three.js on stack overflow, and in particular the suggestions about |
That's kind of a longshot but I've modified my local three.js file ( On line 17,162 I've altered the function function reversePainterSortStable( a, b ) {
if ( a.renderOrder !== b.renderOrder ) {
return a.renderOrder - b.renderOrder;
} if ( a.z !== b.z ) {
return b.z - a.z;
} else {
// In case the objects are of type Mesh we'll sort by mesh size
// that why we might solve the transparency render order issue
if (a.object && a.object.isMesh && b.object && b.object.isMesh )
return getObjectSize(a) - getObjectSize(b);
else return a.id - b.id;
}
} And I've added a new function: function getObjectSize(obj) {
var box = new THREE.Box3().setFromObject(obj.object);
var target = new THREE.Vector3( 0, 0, 0 );
box.getSize(target);
return target.length();
} @mrdoob is it even worth a Pull-Request? |
@ranbuch Your approach would only fix your use case. It would break all other use cases (objects not in the same position). However, combining your intention with the one in #13857... One approach would be to take the object's center and displace that point towards the camera using the |
I agree that it would work only in case an object is inside another bigger object but the current fallback behavior is sorting by Any why, I have tried your approach, witch is the right one no doubt but again, not sure about my implementation. It's working for my GLB and the case from #13857 jsfiddle here Unfortunately, the solution involves adding a global variable (I'm not a fan) on line var CurrentCamera = null; Assigning the camera on line CurrentCamera = camera; Altering the function reversePainterSortStable( a, b ) {
if ( a.renderOrder !== b.renderOrder ) {
return a.renderOrder - b.renderOrder;
} if (CurrentCamera && a.object && a.object.isMesh && b.object && b.object.isMesh ) {
// In case the objects are of type Mesh we'll sort by mesh size
// that why we might solve the transparency render order issue
return getDistanceFromCamera(b, CurrentCamera) - getDistanceFromCamera(a, CurrentCamera);
} else if ( a.z !== b.z ) {
return b.z - a.z;
}
else return a.id - b.id;
} And adding a new function called function getDistanceFromCamera(object, camera) {
var distance = new THREE.Vector3();
distance.subVectors(camera.position, object.geometry.boundingSphere.center);
return distance.length();
} @mrdoob what do you think? |
On second thought, I'm taking the Would it matter? Can 2 Meshes overlap? |
They sure can. But, unless we implement order-independent-transparency, we won't be able to produce the correct result. |
@ranbuch Sorting by |
Sure will. @mrdoob so you think this solution won't work? Should I just stop wasting your time and leave the rest to you guys? |
Sorry, but the problem is way more complex than that. Unfortunately transparency is still a unsolved problem in realtime computer graphics. In order to understand the problem you need to understand how GPUs draw things on the screen and what the z-buffer is. This talk by @unconed may be a good start: https://acko.net/tv/webglmath/ |
Any chance you can share screenshots of how these libraries/applications display your model? That's be super helpful!
Yeah, that's why I was wondering what logic all these other engines use. |
Sure, I'm on it |
I haven't tried the others, but I don't think Babylon handled it better. Sure, you can see the transparency, but as you rotate the bottle it jumps in and out in a big way. No transparency looks better than that, in my opinion. |
Next is Next is Microsoft with their mixed reality viewer (same as Next is gltf viewer android app: I'm still working on getting the original file that this The last one is It's also working for this example: and this one as well: Looks good but:
If the author wishes to continue experimenting this direction I will do so. Any why, obviously, if it's working on 3 examples it doesn't mean anything. If anything I would suggest offering this approach as a secondary why to render scene in case the developer is explicitly asking for it in additional to the Something like |
Yo only need to open the developer console to see they are using three.js 😁 |
Actually. Because we use ids in the sort, you can work around this issue by changing the order of the objects in the scene in your authoring tool. |
I'm not sure what do you mean by that. The sort might change according to the camera position, model position, animations . . .? I'm sure I can improve the complexity at least somewhat by indexing the nested meshes and maybe re-index by somehow intercepting on scene changes? I'm not that concerned with the performance at the time, I'm just not sure if the is right why. Are there some other sources / examples (with transparency) you can direct me too so I can further test the sorting mechanism? |
What software did you use to create the model? |
Here's the most complex transparent situation I can think of: |
If I'm not mistaken it was done with
looks complecated enought for now 😉 |
BTW this is how it looks like with the current solution: |
I know that's not a general solution but theoretically, If I'll join the 2 meshes together there wont be any sorting to do. That would solve the problem for scenes that can afford merging their meshes to a single mesh. Tried something but it's terrible, I'll think of something else . . . |
That's incorrect. These spheres are double sided, so the back of the spheres should be renderer first. GPUs do not sort triangles so that's why you see some stripes. Some triangles in the front get rendered before triangles on the back. |
I realize the screenshot I attached is misleading. I didn't say that it's incorrect. |
Put aside this model issues, I've improved my solution performance so no frames should be dropped.
Also, I've solved this glitch. Keep in mind that for the sorting mechanize to work the THREE.WebGLRenderer({transparentSortLogic: THREE.CAMERA_PROXIMITY}); when Do you want me to create a PR? |
Something like |
So you want the developer to write the sorting functions? |
O.K. I've changed |
I didn't get super crazy different results with different transparency sorting, but other objects intersecting this model do render differently: re:
I wonder how much of this is the responsibility of the "engine". There are probably many algorithms, and much different logic that can be applied to solve this problem (and other problems). Rather than reverse engineering some other engine, i prefer to experiment with three.js. The "core" of three is perfect for this, the "engine" part is not. I can hack away with shaders, the gl context but eventually you hit a wall. For example, this approach to transparency uses the stencil buffer, without it i'm not sure if it could even be considered for some kind of production. Three has abstractions for depth ops but not for stencil ops. Render targets use their own stencil buffers and three gets in the way of sharing them, which is something that is possible with WebGL. I'm much more shocked by this than transparency (which is complex) failing if that makes sense :) Other examples that fall in this category are normal maps, and shader chunks. I'm not sure what exactly makes the "engine" in three's context. My guess is something that:
meaning that keeping the existing On the other hand if i consider some kind of a "core" that is super flexible and extensible, one could do:
But the way three.js is built now this seems impossible to do. I don't know how other packages do it but i've seen things get refactored and split into different repositories and such. Bottom line, it's much easier to pinpoint:
Than
:) |
Description of the problem
Browser
OS
Here is a GLB file that contains a Glenfiddich bottle 3D model.
The bottle is transparent so you can see the liquid inside of it.
When viewing on babylonjs you can actually see the liquid inside but on threejs you cannot see the bottle transparency.
The text was updated successfully, but these errors were encountered: