SoftParticles.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import { Fn, float, positionView, viewportDepthTexture, perspectiveDepthToViewZ, cameraNear, cameraFar } from 'three/tsl';
  2. /**
  3. * @module SoftParticles
  4. * @three_import import { softParticles } from 'three/addons/tsl/utils/SoftParticles.js';
  5. */
  6. /**
  7. * A symmetric contrast curve, as described in the "Soft Particles" white paper
  8. * (NVIDIA, Tristan Lorach).
  9. *
  10. * @tsl
  11. * @function
  12. * @private
  13. * @param {Node<float>} input - The value to remap, expected in the `[0, 1]` range.
  14. * @param {Node<float>} power - The contrast power. `1` is linear, higher values sharpen the transition.
  15. * @return {Node<float>} The remapped value.
  16. */
  17. const contrastCurve = /*@__PURE__*/ Fn( ( [ input, power ] ) => {
  18. const aboveHalf = input.greaterThan( 0.5 ).toConst();
  19. const folded = aboveHalf.select( input.oneMinus(), input ).toConst();
  20. const output = folded.mul( 2 ).saturate().pow( power ).mul( 0.5 ).toConst();
  21. return aboveHalf.select( output.oneMinus(), output );
  22. } ).setLayout( {
  23. name: 'contrastCurve',
  24. type: 'float',
  25. inputs: [
  26. { name: 'input', type: 'float' },
  27. { name: 'power', type: 'float' }
  28. ]
  29. } );
  30. /**
  31. * Computes an opacity node for soft particles, based on the "Soft Particles" white
  32. * paper (NVIDIA, Tristan Lorach).
  33. *
  34. * @tsl
  35. * @function
  36. * @param {Object} [parameters={}] - The configuration parameters.
  37. * @param {Node<float>} [parameters.opacity=float(1)] - The sprite's base opacity, which the soft fade is multiplied with.
  38. * @param {Node<float>|number} [parameters.distance=1] - The world-space distance over which the sprite fades out against the scene.
  39. * @param {Node<float>|number} [parameters.contrast=2] - The contrast power of the fade curve. `1` is linear, higher values sharpen the transition.
  40. * @param {Node<float>} [parameters.viewportDepth=viewportDepthTexture()] - The opaque scene depth the particles fade against.
  41. * @return {Node<float>} The opacity node to assign to `material.opacityNode`.
  42. */
  43. export function softParticles( { opacity = float( 1 ), distance = 1, contrast = 2, viewportDepth = viewportDepthTexture() } = {} ) {
  44. // Read the opaque scene depth captured before the particle pass and convert both
  45. // the scene depth and the particle's depth to view space, so the gap between them
  46. // can be measured in world units.
  47. const sceneViewZ = perspectiveDepthToViewZ( viewportDepth, cameraNear, cameraFar ).toConst();
  48. const depthDelta = positionView.z.sub( sceneViewZ ).div( distance ).saturate();
  49. // Fade out as the particle approaches the scene; stay opaque when well in front of it.
  50. return opacity.mul( contrastCurve( depthDelta, contrast ) );
  51. }
粤ICP备19079148号