BumpMapNode.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import TempNode from '../core/TempNode.js';
  2. import { addNodeClass } from '../core/Node.js';
  3. import { uv } from '../accessors/UVNode.js';
  4. import { normalView } from '../accessors/NormalNode.js';
  5. import { positionView } from '../accessors/PositionNode.js';
  6. import { faceDirection } from './FrontFacingNode.js';
  7. import { tslFn, nodeProxy, float, vec2 } from '../shadernode/ShaderNode.js';
  8. // Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen
  9. // https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf
  10. // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)
  11. const dHdxy_fwd = tslFn( ( { textureNode, bumpScale } ) => {
  12. let texNode = textureNode;
  13. if ( texNode.isTextureNode !== true ) {
  14. texNode.traverse( ( node ) => {
  15. if ( node.isTextureNode === true ) texNode = node;
  16. } );
  17. }
  18. if ( texNode.isTextureNode !== true ) {
  19. throw new Error( 'THREE.TSL: dHdxy_fwd() requires a TextureNode.' );
  20. }
  21. const Hll = float( textureNode );
  22. const uvNode = texNode.uvNode || uv();
  23. // It's used to preserve the same TextureNode instance
  24. const sampleTexture = ( uv ) => textureNode.cache().context( { getUVNode: () => uv } );
  25. return vec2(
  26. float( sampleTexture( uvNode.add( uvNode.dFdx() ) ) ).sub( Hll ),
  27. float( sampleTexture( uvNode.add( uvNode.dFdy() ) ) ).sub( Hll )
  28. ).mul( bumpScale );
  29. } );
  30. const perturbNormalArb = tslFn( ( inputs ) => {
  31. const { surf_pos, surf_norm, dHdxy } = inputs;
  32. const vSigmaX = surf_pos.dFdx();
  33. const vSigmaY = surf_pos.dFdy();
  34. const vN = surf_norm; // normalized
  35. const R1 = vSigmaY.cross( vN );
  36. const R2 = vN.cross( vSigmaX );
  37. const fDet = vSigmaX.dot( R1 ).mul( faceDirection );
  38. const vGrad = fDet.sign().mul( dHdxy.x.mul( R1 ).add( dHdxy.y.mul( R2 ) ) );
  39. return fDet.abs().mul( surf_norm ).sub( vGrad ).normalize();
  40. } );
  41. class BumpMapNode extends TempNode {
  42. constructor( textureNode, scaleNode = null ) {
  43. super( 'vec3' );
  44. this.textureNode = textureNode;
  45. this.scaleNode = scaleNode;
  46. }
  47. setup() {
  48. const bumpScale = this.scaleNode !== null ? this.scaleNode : 1;
  49. const dHdxy = dHdxy_fwd( { textureNode: this.textureNode, bumpScale } );
  50. return perturbNormalArb( {
  51. surf_pos: positionView,
  52. surf_norm: normalView,
  53. dHdxy
  54. } );
  55. }
  56. }
  57. export default BumpMapNode;
  58. export const bumpMap = nodeProxy( BumpMapNode );
  59. addNodeClass( 'BumpMapNode', BumpMapNode );