NormalMapNode.js 2.5 KB

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