NormalMapNode.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import PositionNode from '../accessors/PositionNode.js';
  2. import NormalNode from '../accessors/NormalNode.js';
  3. import UVNode from '../accessors/UVNode.js';
  4. import MathNode from '../math/MathNode.js';
  5. import OperatorNode from '../math/OperatorNode.js';
  6. import FloatNode from '../inputs/FloatNode.js';
  7. import TempNode from '../core/TempNode.js';
  8. import ModelNode from '../accessors/ModelNode.js';
  9. import { ShaderNode, cond, add, mul, dFdx, dFdy, cross, max, dot, normalize, inversesqrt, equal } from '../ShaderNode.js';
  10. import { TangentSpaceNormalMap, ObjectSpaceNormalMap } from 'three';
  11. // Normal Mapping Without Precomputed Tangents
  12. // http://www.thetenthplanet.de/archives/1180
  13. const perturbNormal2ArbNode = new ShaderNode( ( inputs ) => {
  14. const { eye_pos, surf_norm, mapN, faceDirection, uv } = inputs;
  15. const q0 = dFdx( eye_pos.xyz );
  16. const q1 = dFdy( eye_pos.xyz );
  17. const st0 = dFdx( uv.st );
  18. const st1 = dFdy( uv.st );
  19. const N = surf_norm; // normalized
  20. const q1perp = cross( q1, N );
  21. const q0perp = cross( N, q0 );
  22. const T = add( mul( q1perp, st0.x ), mul( q0perp, st1.x ) );
  23. const B = add( mul( q1perp, st0.y ), mul( q0perp, st1.y ) );
  24. const det = max( dot( T, T ), dot( B, B ) );
  25. const scale = cond( equal( det, 0 ), 0, mul( faceDirection, inversesqrt( det ) ) );
  26. return normalize( add( mul( T, mul( mapN.x, scale ) ), mul( B, mul( mapN.y, scale ) ), mul( N, mapN.z ) ) );
  27. } );
  28. class NormalMapNode extends TempNode {
  29. constructor( node ) {
  30. super( 'vec3' );
  31. this.node = node;
  32. this.normalMapType = TangentSpaceNormalMap;
  33. }
  34. generate( builder ) {
  35. const type = this.getNodeType( builder );
  36. const normalMapType = this.normalMapType;
  37. const normalOP = new OperatorNode( '*', this.node, new FloatNode( 2.0 ).setConst( true ) );
  38. const normalMap = new OperatorNode( '-', normalOP, new FloatNode( 1.0 ).setConst( true ) );
  39. if ( normalMapType === ObjectSpaceNormalMap ) {
  40. const vertexNormalNode = new OperatorNode( '*', new ModelNode( ModelNode.NORMAL_MATRIX ), normalMap );
  41. const normal = new MathNode( MathNode.NORMALIZE, vertexNormalNode );
  42. return normal.build( builder, type );
  43. } else if ( normalMapType === TangentSpaceNormalMap ) {
  44. const perturbNormal2ArbCall = perturbNormal2ArbNode( {
  45. eye_pos: new PositionNode( PositionNode.VIEW ),
  46. surf_norm: new NormalNode( NormalNode.VIEW ),
  47. mapN: normalMap,
  48. faceDirection: new FloatNode( 1.0 ).setConst( true ),
  49. uv: new UVNode()
  50. } );
  51. return perturbNormal2ArbCall.build( builder, type );
  52. }
  53. }
  54. }
  55. export default NormalMapNode;