NormalMapNode.js 2.2 KB

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