Raymarching.js 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import { varying, vec4, modelWorldMatrixInverse, cameraPosition, positionGeometry, float, Fn, Loop, max, min, vec2, vec3 } 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. };
粤ICP备19079148号