NormalMapNode.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import TempNode from '../core/TempNode.js';
  2. import { add } from '../math/OperatorNode.js';
  3. import { modelNormalMatrix } from '../accessors/ModelNode.js';
  4. import { normalView } from '../accessors/NormalNode.js';
  5. import { positionView } from '../accessors/PositionNode.js';
  6. import { TBNViewMatrix } from '../accessors/AccessorsUtils.js';
  7. import { uv } from '../accessors/UVNode.js';
  8. import { faceDirection } from './FrontFacingNode.js';
  9. import { addNodeClass } from '../core/Node.js';
  10. import { addNodeElement, tslFn, nodeProxy, vec3 } from '../shadernode/ShaderNode.js';
  11. import { TangentSpaceNormalMap, ObjectSpaceNormalMap } from 'three';
  12. // Normal Mapping Without Precomputed Tangents
  13. // http://www.thetenthplanet.de/archives/1180
  14. const perturbNormal2Arb = tslFn( ( inputs ) => {
  15. const { eye_pos, surf_norm, mapN, uv } = inputs;
  16. const q0 = eye_pos.dFdx();
  17. const q1 = eye_pos.dFdy();
  18. const st0 = uv.dFdx();
  19. const st1 = uv.dFdy();
  20. const N = surf_norm; // normalized
  21. const q1perp = q1.cross( N );
  22. const q0perp = N.cross( q0 );
  23. const T = q1perp.mul( st0.x ).add( q0perp.mul( st1.x ) );
  24. const B = q1perp.mul( st0.y ).add( q0perp.mul( st1.y ) );
  25. const det = T.dot( T ).max( B.dot( B ) );
  26. const scale = faceDirection.mul( det.inverseSqrt() );
  27. return add( T.mul( mapN.x, scale ), B.mul( mapN.y, scale ), N.mul( mapN.z ) ).normalize();
  28. } );
  29. class NormalMapNode extends TempNode {
  30. constructor( node, scaleNode = null ) {
  31. super( 'vec3' );
  32. this.node = node;
  33. this.scaleNode = scaleNode;
  34. this.normalMapType = TangentSpaceNormalMap;
  35. }
  36. setup( builder ) {
  37. const { normalMapType, scaleNode } = this;
  38. let normalMap = this.node.mul( 2.0 ).sub( 1.0 );
  39. if ( scaleNode !== null ) {
  40. normalMap = vec3( normalMap.xy.mul( scaleNode ), normalMap.z );
  41. }
  42. let outputNode = null;
  43. if ( normalMapType === ObjectSpaceNormalMap ) {
  44. outputNode = modelNormalMatrix.mul( normalMap ).normalize();
  45. } else if ( normalMapType === TangentSpaceNormalMap ) {
  46. const tangent = builder.hasGeometryAttribute( 'tangent' );
  47. if ( tangent === true ) {
  48. outputNode = TBNViewMatrix.mul( normalMap ).normalize();
  49. } else {
  50. outputNode = perturbNormal2Arb( {
  51. eye_pos: positionView,
  52. surf_norm: normalView,
  53. mapN: normalMap,
  54. uv: uv()
  55. } );
  56. }
  57. }
  58. return outputNode;
  59. }
  60. }
  61. export default NormalMapNode;
  62. export const normalMap = nodeProxy( NormalMapNode );
  63. addNodeElement( 'normalMap', normalMap );
  64. addNodeClass( 'NormalMapNode', NormalMapNode );