Search code examples
three.jswebgltransparencyz-order

Ordering of transparent ParticleSystem with BufferGeometry in Threejs


Related to this question : Z-buffer issue with BufferGeometry in ParticleSystem

The given solution does not work for me, I made my own shader for rendering as I added custom attributes for size and UV. Everythinf works fine with the buffer geometry except the particle ordering for transparency.

If Activated > squared texture are partly hiding the other particles.

If Deactivated (depthTest : false) > particles looks fine but are not ordered.

Thanks for your answer, the subject has been raised several times but nothing worked for me yet.

Using Three.js 61

            particleMaterial = new THREE.ShaderMaterial({
                    fragmentShader    : document.getElementById("sectorPointFragment").textContent,
                    vertexShader  : document.getElementById("sectorPointVertex").textContent,
                    uniforms  : uniforms,
                    attributes : attributes,
                    transparent : true,
                    alphaTest : 0.5
                });         


            _this.particles = new THREE.ParticleSystem(geometry, particleMaterial);

            _this.particles.sortParticles = true;   

Solution

  • So here is the solution I took, creating a new array with value each time. Seems to work, tested with 1000 particles not more

    this.updateShaders = function() {
        if(clock.getElapsedTime() - _lastZOrdering <= 0.2) {
            return;
        }
        // z-ordering
        var distances = [],
            attributes = this.particles.geometry.attributes,
            nbParticle = attributes.position.numItems / 3,
            tmpPos = new THREE.Vector3(0, 0, 0);
    
        for (var i = 0; i < nbParticle; ++i) {
            tmpPos.set(
                attributes.position.array[i * 3],
                attributes.position.array[i * 3 + 1],
                attributes.position.array[i * 3 + 2]
            );
            distances[i] = [this.controls.object.position.distanceTo(tmpPos), i];
        }
        distances.sort(function(a, b){ 
            return b[0] - a[0];
        });
    
        var index, indexSrc, indexDst, tmpTab;
        for (var val in attributes) {
            tmpTab = new Float32Array(attributes[val].itemSize * nbParticle);
            for(i = 0; i < nbParticle; ++i){
                index = distances[i][1];
                for(j = 0; j < attributes[val].itemSize; ++j){
                    indexSrc = index * attributes[val].itemSize + j;
                    indexDst = i * attributes[val].itemSize + j;
                    tmpTab[indexDst] = attributes[val].array[indexSrc];
                }
            }
            attributes[val].array = tmpTab;
            attributes[val].needsUpdate = true;
        }
        _lastZOrdering = clock.getElapsedTime();
    }