Transparent object issue

Hi, I’m new to Three.js so maybe it’s simple case, but let me ask :slight_smile:

I’m trying to create a simple scene composed of multiple objects using spacekit.js, which relies on three.js underneath.

While presenting the objects, I have encountered few issues. I’d greatly appreciate guidance on what I can change or check to achieve intended effect.

  1. The ‘green’ object (screenshots below) is created using LatheGeometry and MeshStandardMaterial with options as below:
    color: {choosenColor},
    side: THREE.DoubleSide,
    transparent: true,
    opacity: {choosenOpacity},

It’s single object with empty space inside. As you can see in the screenshots below (#1, #2), depending on the camera’s position, part of the inner edge is clipped or even not visible. How can I achieve an effect where the edges of the inner opening are always visible regardless of the camera’s position (as in the last screenshot #3)?

  1. Two ‘green’ objects (screenshot below) are created similarly to the single one described above. In this case, the ‘recess’ in the objects is not visible from every angle but depends on the camera’s position, sometimes it is not visible, sometimes is clipped (screenshot #1 - ‘recess’ of left object is partially clipped). How can I ensure that the ‘recess’ is always visible?

    1. Each of the ‘orange’ objects (screenshot below) is created using LatheGeometry and MeshStandardMaterial with options as below:
    color: {choosenColor},
    side: THREE.DoubleSide,

As you can see in the screenshot below, there is noticeable edge tearing when they intersect with other objects (green ones with transparent set to true, desribed above). How can I avoid this tearing and achieve smooth effect when objects intersect?

So far, I have tried adjusting renderOrder, using computeVertexNormals, setting depthWrite, depthTest for materials. However, I haven’t been able to achieve desired results.

All suggestions will be greatly appreciated. Thank you for any help :slight_smile:

Depending on the release of Three you use, you will benefit from one of the newer as DoubleSide ist rendered in 2 passes avoiding triangle order issues that naturally come at one draw call in such cases.

However in cases like having a sphere inside a sphere that is a single geometry it’s more difficult, as the double passt Backside/Frontside is rather for hollow objectes, you would have to make sure that the triangle order of the geometry is sorted in a way the triangles of the inner geometry come all first, then there should be no issue.

The last issue however might be precision issues from huge or tiny scales, either try use somewhat 32bit reasonable scales or use the rawhammer logarithmicDepthBuffer: true option on the renderer options that might even suit to your usecase if you need large units.

I use version 0.129 for the Three, which spacekit.js relies on, so I can’t update it.

As for the first two issues, your idea turned out to be brilliant - reversing the arrays of points that create objects (single and doubles) ensures that the empty space/indentation is always visible. Thank you so much! :slight_smile:

Regarding the last issue, setting logarithmicDepthBuffer: true, unfortunately didn’t solve the problem. Do you have any other ideas? Maybe some changes related to the material?

When it comes to a single object with empty space inside, I noticed one issue (details in the screenshots). One side of the walls creating the empty space inside is brighter (screenshots below), but only when the object’s opacity is different from 1. Any thoughts on what might be causing this, or what I should check?

Thank you once again! :slight_smile:

It might also be worth trying depthWrite: false on your transparent materials.

Like @donmccurdy said you also should disable depthWrite for transparent materials, for internal geometry clipping though there isn’t a way around 2 drawcalls for each side depending on the blending mode as double side triangles render always in the order of the geometry triangles, if both sides are visible at once (unlike billboards for instance) they can clip each other.

It can be also archived by using the material twice on it as array, one with Backside one with FrontSide, and 2 geometry groups with the full length of the geometry (might work without groups too though)

mesh.material = [ BackSideMaterial, FrontSideMaterial];

The first having side: THREE.BackSide and the second side: THREE.FrontSide.

Long, long time ago (where was no WebGL at that time, only OpenGL 1.x), I used to nest transparent objects by rendering their back faces (from outermost to innermost) and then rendering their front faces (from innermost to outermost). This is not a bullet-proof technique, but works if objects are nested like Matryoshka dolls and if there are no (self-)intersections.

Here is an attempt to recreate this approach with three nested spheres using the old Three.js r129: