Hello, just yesterday I did)

I had to look for a long time, tried, but still managed to do, now I want to share with all that I have. There are some jambs but in general everything works fine.

First you need to create a Depth `depthRenderTarget`

that’s pretty easy

```
var depthMaterial = new THREE.MeshDepthMaterial();
depthMaterial.depthPacking = THREE.RGBADepthPacking;
depthMaterial.blending = THREE.NoBlending;
depthMaterial.side = THREE.DoubleSide;
var depthRenderTarget = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
});
```

Now in the loop you need to do this before rendering the main scene

```
scene.add(depthBox);
depthBox.position.copy(camera.position);
scene.overrideMaterial = depthMaterial;
renderer.render( scene, camera, depthRenderTarget, true );
scene.overrideMaterial = null;
scene.remove(depthBox);
.....
renderer.render( scene, camera);
```

But there was a problem, the fact is that if the background is empty then soft particles would hide completely.

I did not know how to fix it and made it simple, I added a box that was attached to the camera.

```
var depthBox = new THREE.Mesh(new THREE.CubeGeometry( 30000, 30000, 30000 ),new THREE.MeshBasicMaterial());
```

Now the shader itself, many tests and tests, but finally it turned out))

For convenience and for other shaders I did so

```
THREE.ShaderChunk['soft_pars_fragment'] = [
'varying vec3 fmvPosition;',
'uniform sampler2D tDepth;',
'uniform float fCamNear;',
'uniform float fCamFar;',
'uniform mat4 fPjMatrix;',
'uniform mat4 fMvMatrix;',
'uniform float fDistance;',
'uniform float fContrast;',
// Transform a worldspace coordinate to a clipspace coordinate
// Note that `mvpMatrix` is: `projectionMatrix * modelViewMatrix`
'vec4 worldToClip( vec3 v, mat4 mvpMatrix ) {',
'return ( mvpMatrix * vec4( v, 1.0 ) );',
'}',
// Transform a clipspace coordinate to a screenspace one.
'vec3 clipToScreen( vec4 v ) {',
'return ( vec3( v.xyz ) / ( v.w * 2.0 ) );',
'}',
// Transform a screenspace coordinate to a 2d vector for
// use as a texture UV lookup.
'vec2 screenToUV( vec2 v ) {',
'return 0.5 - vec2( v.xy ) * -1.0;',
'}',
//I really do not know how this function works
'float readDepth( float z ) {',
'float cameraFarPlusNear = fCamFar + fCamNear;',
'float cameraFarMinusNear = fCamFar - fCamNear;',
'float cameraCoef = 2.0 * fCamNear;',
'return cameraCoef / ( cameraFarPlusNear - z * cameraFarMinusNear );',
'}',
//Function for calculating fade
'float calculateFade(vec2 pixelPosition, float particleDepth){',
'float zFade = 1.0;',
'float sceneDepth = readDepth( unpackRGBAToDepth( texture2D( tDepth, pixelPosition ) ) );',
'float inputDepth = ((sceneDepth - particleDepth) * fDistance);',
'if ((inputDepth < 1.0) && (inputDepth > 0.0)){',
// Make it fade smoothly from 0 and 1 - I think I grabbed this curve from some nVidia paper
'zFade = 0.5 * pow(saturate(2.0*((inputDepth > 0.5) ? (1.0 - inputDepth) : inputDepth)), fContrast);',
'zFade = (inputDepth > 0.5) ? (1.0 - zFade) : zFade;',
'}',
'else{',
'zFade = saturate(inputDepth);',
'}',
'return zFade;',
'}',
].join("\n\n");
THREE.ShaderChunk['soft_fragment'] = [
'vec4 csp = worldToClip( fmvPosition, fPjMatrix * fMvMatrix );',
'vec3 scp = clipToScreen( csp );',
'gl_FragColor.a *= calculateFade( screenToUV( scp.xy ), readDepth( gl_FragCoord.z ) );',
].join("\n\n");
THREE.ShaderChunk['soft_pars_vertex'] = 'varying vec3 fmvPosition;';
THREE.ShaderChunk['soft_vertex'] = 'fmvPosition = mvPosition.xyz;';
THREE.UniformsLib['soft'] = {
tDepth: { type: "t", value: null },
fCamNear: { type: "f", value: 1 },
fCamFar: { type: "f", value: 1000 },
fPjMatrix: { type: 'm4', value: null },
fMvMatrix: { type: 'm4', value: null},
fContrast: { type: 'f', value: 1.0 },
fDistance: { type: 'f', value: 50.0 },
}
```

It’s simpler then, we create the shader with the material

```
var shaderSoft = {
uniforms: { },
vertexShader: [
'varying vec2 vUv;',
'#include <soft_pars_vertex>',
'void main(){',
'vUv = uv;',
'vec4 mvPosition = modelViewMatrix * vec4(position, 1.0 );',
'#include <soft_vertex>',
'gl_Position = projectionMatrix * mvPosition;',
'}',
].join("\n"),
fragmentShader: [
'#include <packing>',
'#include <soft_pars_fragment>',
'void main(){',
'vec4 col = texture2D(tDiffuse, vUv.xy);',
'col.a *= opacity;',
'gl_FragColor = col;',
'#include <soft_fragment>',
'}'
].join("\n")
}
var uniforms = THREE.UniformsUtils.merge([
THREE.UniformsLib['soft'],
{
opacity: {type: 'f', value: 1.0},
tDiffuse: {type: 't', value: null}
}
];
uniforms.tDiffuse.value = new THREE.TextureLoader().load( 'texture.png' );
uniforms.tDepth.value = depthRenderTarget.texture;
uniforms.fPjMatrix.value = camera.projectionMatrix;
uniforms.fMvMatrix.value = (new THREE.Matrix4()).multiplyMatrices( camera.matrixWorldInverse, camera.matrixWorld );
var material = new THREE.ShaderMaterial({
uniforms : uniforms,
vertexShader : shaderSoft.vertexShader,
fragmentShader : shaderSoft.fragmentShader,
});
material.depthTest = false;
material.transparent = true;
```

Be sure to turn off the depth check `depthTest = false`

Also specify the depth texture obtained from `depthRenderTarget`

```
uniforms.tDepth.value = depthRenderTarget.texture
```

`uniforms.fDistance`

Adjusts how much the fade will be, if the number is less then the fade will be greater.

`fPjMatrix and fMvMatrix`

I do not know what it is, it is necessary for the co-correction of UV

Here is the source https://stackoverflow.com/questions/26576429/projecting-fbo-value-to-screen-space-to-read-from-depth-texture

But sometimes at some angles it is noticeable that the UV is incorrectly defined, but it is almost not noticeable.

Next, I did not know how to turn off depth rendering for transparent objects, so I did a better job, found the required line in the library and ordered it.

```
//if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera, overrideMaterial );
```

Now I’m happy with the result, for particles this is what you need, and also to simulate the ambient light, too, will sweat.

Yes, it would be great, I like the result and I would like to see if there was such a plug-in in the library)

I offered a post on github:

https://github.com/mrdoob/three.js/issues/11589