Question

When you have two planes in Three.js / WebGL and one or both of them are transparent, sometimes the plane behind will be hidden by the transparent plane above. Why is this?

Was it helpful?

Solution

This is not a bug, it's just how OpenGL (and, hence, WebGL) works. Transparent surfaces don't play well with the z-buffer, and as such must be manually sorted and rendered back-to-front. Three JS is attempting to do this for you (which is why the problem goes away when you set the X value > 0) but cannot robustly handle the case of intersecting geometry like you're showing.

I've explained the issue more in-depth in a different SO question, so you may want to reference that.

OTHER TIPS

Let's say that you are using some transparent *.png image. Then this would help:

new THREE.MeshBasicMaterial( { side:THREE.BackSide,map:texture, depthWrite: false, depthTest: false });

Setting the depthWrite property to false solved my issue.

new THREE.MeshBasicMaterial({ 
    opacity: 0.25, 
    transparent: true, 
    side: THREE.DoubleSide, 
    depthWrite: false
});

Try adding alphaTest: 0.5 to the material.

fwiw, if you have lots of parallel planes (can't see your sample, google can't resolve your domain), it's easy to keep them sorted along the perpendicular axis. For a list of planes [A B C D] the order-to-draw will be either [A B C D] or [D C B A] and nothing else! So there need not be a performance hit from sorting. Just keep them in order as you go.

Setting Mesh renderOrder to solve my problem, below is my code, you can modify node.renderOrder value:

loader.load(model_url, (gltf)=>{
            let scene = gltf.scene

            scene.traverse((node)=>{

                if(node.isMesh){
                    node.material.transparent = true

                    if(node.name === 'car_windows'){
                        node.material.opacity = 0.4
                        node.material.side = 0
                        node.renderOrder = 110
                    }

                    if(node.name === 'car_body'){
                        node.material.opacity = 0.4
                        node.renderOrder = 100
                    }

                    if(node.name === 'car_seats'){
                        node.material.opacity = .5
                        node.renderOrder = 90
                    }

                    mesh_arr.push(node)
                    mesh_objs[node.name] = node
                }
            })
})

This worked for me, don't use the literal boolean value true try using 1 instead.

object3d.material.transparent = 1; 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top