Raymarching.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import { varying, vec4, modelWorldMatrixInverse, cameraPosition, positionGeometry, float, Fn, Loop, max, min, vec2, vec3, smoothstep, If, Break } from 'three/tsl';
  2. const hitBox = /*@__PURE__*/ Fn( ( { orig, dir } ) => {
  3. const box_min = vec3( - 0.5 );
  4. const box_max = vec3( 0.5 );
  5. const inv_dir = dir.reciprocal();
  6. const tmin_tmp = box_min.sub( orig ).mul( inv_dir );
  7. const tmax_tmp = box_max.sub( orig ).mul( inv_dir );
  8. const tmin = min( tmin_tmp, tmax_tmp );
  9. const tmax = max( tmin_tmp, tmax_tmp );
  10. const t0 = max( tmin.x, max( tmin.y, tmin.z ) );
  11. const t1 = min( tmax.x, min( tmax.y, tmax.z ) );
  12. return vec2( t0, t1 );
  13. } );
  14. /**
  15. * Performs raymarching box-area using the specified number of steps and a callback function.
  16. *
  17. * ```js
  18. * RaymarchingBox( count, ( { positionRay } ) => {
  19. *
  20. * } );
  21. * ```
  22. *
  23. * @tsl
  24. * @function
  25. * @param {number|Node} steps - The number of steps for raymarching.
  26. * @param {Function|FunctionNode} callback - The callback function to execute at each step.
  27. * @returns {void}
  28. */
  29. export const RaymarchingBox = ( steps, callback ) => {
  30. const vOrigin = varying( vec3( modelWorldMatrixInverse.mul( vec4( cameraPosition, 1.0 ) ) ) );
  31. const vDirection = varying( positionGeometry.sub( vOrigin ) );
  32. const rayDir = vDirection.normalize();
  33. const bounds = vec2( hitBox( { orig: vOrigin, dir: rayDir } ) ).toVar();
  34. bounds.x.greaterThan( bounds.y ).discard();
  35. bounds.assign( vec2( max( bounds.x, 0.0 ), bounds.y ) );
  36. const inc = vec3( rayDir.abs().reciprocal() ).toVar();
  37. const delta = float( min( inc.x, min( inc.y, inc.z ) ) ).toVar( 'rayDelta' ); // used 'rayDelta' name in loop
  38. delta.divAssign( float( steps ) );
  39. const positionRay = vec3( vOrigin.add( bounds.x.mul( rayDir ) ) ).toVar();
  40. Loop( { type: 'float', start: bounds.x, end: bounds.y, update: '+= rayDelta' }, () => {
  41. callback( { positionRay } );
  42. positionRay.addAssign( rayDir.mul( delta ) );
  43. } );
  44. };
  45. /**
  46. * Performs raymarching on the specified 3D texture.
  47. *
  48. * @tsl
  49. * @function
  50. * @param {Object} params - The parameters for the function.
  51. * @param {Texture|Node} params.texture - The 3D texture to sample.
  52. * @param {number|Node} [params.range=0.1] - The range for the smoothstep function.
  53. * @param {number|Node} [params.threshold=0.25] - The threshold for the smoothstep function.
  54. * @param {number|Node} [params.opacity=0.25] - The opacity value for the final color.
  55. * @param {number|Node} [params.steps=100] - The number of steps for raymarching.
  56. * @returns {Function} The generated function that performs raymarching on the 3D texture.
  57. */
  58. export const raymarchingTexture3D = Fn( ( {
  59. texture,
  60. range = float( 0.1 ),
  61. threshold = float( 0.25 ),
  62. opacity = float( 0.25 ),
  63. steps = float( 100 )
  64. } ) => {
  65. const finalColor = vec4( 0 ).toVar();
  66. RaymarchingBox( steps, ( { positionRay } ) => {
  67. const mapValue = float( texture.sample( positionRay.add( 0.5 ) ).r ).toVar();
  68. mapValue.assign( smoothstep( threshold.sub( range ), threshold.add( range ), mapValue ).mul( opacity ) );
  69. const shading = texture.sample( positionRay.add( vec3( - 0.01 ) ) ).r.sub( texture.sample( positionRay.add( vec3( 0.01 ) ) ).r );
  70. const col = shading.mul( 3.0 ).add( positionRay.x.add( positionRay.y ).mul( 0.25 ) ).add( 0.2 );
  71. finalColor.rgb.addAssign( finalColor.a.oneMinus().mul( mapValue ).mul( col ) );
  72. finalColor.a.addAssign( finalColor.a.oneMinus().mul( mapValue ) );
  73. If( finalColor.a.greaterThanEqual( 0.95 ), () => {
  74. Break();
  75. } );
  76. } );
  77. return finalColor;
  78. } );
粤ICP备19079148号