NormalMapNode.js 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  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, join, 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. // Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988
  16. const q0 = join( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );
  17. const q1 = join( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );
  18. const st0 = dFdx( uv.st );
  19. const st1 = dFdy( uv.st );
  20. const N = surf_norm; // normalized
  21. const q1perp = cross( q1, N );
  22. const q0perp = cross( N, q0 );
  23. const T = add( mul( q1perp, st0.x ), mul( q0perp, st1.x ) );
  24. const B = add( mul( q1perp, st0.y ), mul( q0perp, st1.y ) );
  25. const det = max( dot( T, T ), dot( B, B ) );
  26. const scale = cond( equal( det, 0 ), 0, mul( faceDirection, inversesqrt( det ) ) );
  27. return normalize( add( mul( T, mul( mapN.x, scale ) ), mul( B, mul( mapN.y, scale ) ), mul( N, mapN.z ) ) );
  28. } );
  29. class NormalMapNode extends TempNode {
  30. constructor( value ) {
  31. super( 'vec3' );
  32. this.value = value;
  33. this.normalMapType = TangentSpaceNormalMap;
  34. }
  35. generate( builder ) {
  36. const type = this.getNodeType( builder );
  37. const normalMapType = this.normalMapType;
  38. const normalOP = new OperatorNode( '*', this.value, new FloatNode( 2.0 ).setConst( true ) );
  39. const normalMap = new OperatorNode( '-', normalOP, new FloatNode( 1.0 ).setConst( true ) );
  40. if ( normalMapType === ObjectSpaceNormalMap ) {
  41. const vertexNormalNode = new OperatorNode( '*', new ModelNode( ModelNode.NORMAL_MATRIX ), normalMap );
  42. const normal = new MathNode( MathNode.NORMALIZE, vertexNormalNode );
  43. return normal.build( builder, type );
  44. } else if ( normalMapType === TangentSpaceNormalMap ) {
  45. const perturbNormal2ArbCall = perturbNormal2ArbNode( {
  46. eye_pos: new PositionNode( PositionNode.VIEW ),
  47. surf_norm: new NormalNode( NormalNode.VIEW ),
  48. mapN: normalMap,
  49. faceDirection: new FloatNode( 1.0 ).setConst( true ),
  50. uv: new UVNode()
  51. } );
  52. return perturbNormal2ArbCall.build( builder, type );
  53. }
  54. }
  55. }
  56. export default NormalMapNode;