NormalMapNode.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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 FunctionNode from '../core/FunctionNode.js';
  9. import ModelNode from '../accessors/ModelNode.js';
  10. import { TangentSpaceNormalMap, ObjectSpaceNormalMap } from 'three';
  11. // Normal Mapping Without Precomputed Tangents
  12. // http://www.thetenthplanet.de/archives/1180
  13. export const perturbNormal2Arb = new FunctionNode( `
  14. vec3 ( vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection, const in vec2 uv ) {
  15. // Workaround for Adreno 3XX dFd*( vec3 ) bug. See #9988
  16. vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );
  17. vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );
  18. vec2 st0 = dFdx( uv.st );
  19. vec2 st1 = dFdy( uv.st );
  20. vec3 N = surf_norm; // normalized
  21. vec3 q1perp = cross( q1, N );
  22. vec3 q0perp = cross( N, q0 );
  23. vec3 T = q1perp * st0.x + q0perp * st1.x;
  24. vec3 B = q1perp * st0.y + q0perp * st1.y;
  25. float det = max( dot( T, T ), dot( B, B ) );
  26. float scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det );
  27. return normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + 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, output ) {
  36. const type = this.getType( builder );
  37. const normalMapType = this.normalMapType;
  38. const nodeData = builder.getDataFromNode( this );
  39. const normalOP = new OperatorNode( '*', this.value, new FloatNode( 2.0 ).setConst( true ) );
  40. const normalMap = new OperatorNode( '-', normalOP, new FloatNode( 1.0 ).setConst( true ) );
  41. if ( normalMapType === ObjectSpaceNormalMap ) {
  42. const vertexNormalNode = new OperatorNode( '*', new ModelNode( ModelNode.NORMAL_MATRIX ), normalMap );
  43. const normal = new MathNode( MathNode.NORMALIZE, vertexNormalNode );
  44. return normal.build( builder, output );
  45. } else if ( normalMapType === TangentSpaceNormalMap ) {
  46. let perturbNormal2ArbCall = nodeData.perturbNormal2ArbCall;
  47. if (perturbNormal2ArbCall === undefined) {
  48. perturbNormal2ArbCall = perturbNormal2Arb.call( {
  49. eye_pos: new PositionNode( PositionNode.VIEW ),
  50. surf_norm: new NormalNode( NormalNode.VIEW ),
  51. mapN: normalMap,
  52. faceDirection: new FloatNode( 1.0 ).setConst( true ),
  53. uv: new UVNode()
  54. } );
  55. nodeData.perturbNormal2ArbCall = perturbNormal2ArbCall;
  56. }
  57. const snippet = perturbNormal2ArbCall.build( builder, output );
  58. return builder.format( snippet, type, output );
  59. }
  60. }
  61. }
  62. export default NormalMapNode;