NormalMapNode.js 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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 SplitNode from '../utils/SplitNode.js';
  10. import JoinNode from '../utils/JoinNode.js';
  11. import { ShaderNode, cond, add, mul, dFdx, dFdy, cross, max, dot, normalize, inversesqrt, equal } from '../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, faceDirection, uv } = inputs;
  17. const q0 = dFdx( eye_pos.xyz );
  18. const q1 = dFdy( eye_pos.xyz );
  19. const st0 = dFdx( uv.st );
  20. const st1 = dFdy( uv.st );
  21. const N = surf_norm; // normalized
  22. const q1perp = cross( q1, N );
  23. const q0perp = cross( N, q0 );
  24. const T = add( mul( q1perp, st0.x ), mul( q0perp, st1.x ) );
  25. const B = add( mul( q1perp, st0.y ), mul( q0perp, st1.y ) );
  26. const det = max( dot( T, T ), dot( B, B ) );
  27. const scale = cond( equal( det, 0 ), 0, mul( faceDirection, inversesqrt( det ) ) );
  28. return normalize( add( mul( T, mul( mapN.x, scale ) ), mul( B, mul( mapN.y, scale ) ), mul( N, mapN.z ) ) );
  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. generate( builder ) {
  38. const type = this.getNodeType( builder );
  39. const { normalMapType, scaleNode } = this;
  40. const normalOP = new OperatorNode( '*', this.node, new FloatNode( 2.0 ).setConst( true ) );
  41. let normalMap = new OperatorNode( '-', normalOP, new FloatNode( 1.0 ).setConst( true ) );
  42. if ( scaleNode !== null ) {
  43. const normalMapScale = new OperatorNode( '*', new SplitNode( normalMap, 'xy'), scaleNode );
  44. normalMap = new JoinNode( [ normalMapScale, new SplitNode( normalMap, 'z' ) ] );
  45. }
  46. if ( normalMapType === ObjectSpaceNormalMap ) {
  47. const vertexNormalNode = new OperatorNode( '*', new ModelNode( ModelNode.NORMAL_MATRIX ), normalMap );
  48. const normal = new MathNode( MathNode.NORMALIZE, vertexNormalNode );
  49. return normal.build( builder, type );
  50. } else if ( normalMapType === TangentSpaceNormalMap ) {
  51. const perturbNormal2ArbCall = perturbNormal2ArbNode( {
  52. eye_pos: new PositionNode( PositionNode.VIEW ),
  53. surf_norm: new NormalNode( NormalNode.VIEW ),
  54. mapN: normalMap,
  55. faceDirection: new FloatNode( 1.0 ).setConst( true ),
  56. uv: new UVNode()
  57. } );
  58. return perturbNormal2ArbCall.build( builder, type );
  59. }
  60. }
  61. }
  62. export default NormalMapNode;