NodeBuilder.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import NodeUniform from './NodeUniform.js';
  2. const VERSION = '1';
  3. class NodeBuilder {
  4. constructor( material, renderer ) {
  5. this.material = material;
  6. this.renderer = renderer;
  7. this.slots = { vertex: [], fragment: [] };
  8. this.defines = { vertex: {}, fragment: {} };
  9. this.uniforms = { vertex: [], fragment: [] };
  10. this.nodesData = new WeakMap();
  11. this.shaderStage = null;
  12. }
  13. setShaderStage( shaderStage ) {
  14. this.shaderStage = shaderStage;
  15. }
  16. addSlot( shader, slot ) {
  17. this.slots[ shader ].push( slot );
  18. }
  19. addDefine( shader, name, value = '' ) {
  20. this.defines[ shader ][ name ] = value;
  21. }
  22. generateVec2( x, y ) {
  23. return `vec2( ${x}, ${y})`;
  24. }
  25. generateVec3( x, y, z ) {
  26. return `vec3( ${x}, ${y}, ${z} )`;
  27. }
  28. generateVec4( x, y, z, w ) {
  29. return `vec4( ${x}, ${y}, ${z}, ${w} )`;
  30. }
  31. generateFloat( value ) {
  32. return value + ( value % 1 ? '' : '.0' );
  33. }
  34. getUniformNSName( nodeUniform ) {
  35. return nodeUniform.name;
  36. }
  37. getTypeLength( type ) {
  38. if ( type === 'float' ) return 1;
  39. else if ( type === 'vec2' ) return 2;
  40. else if ( type === 'vec3' ) return 3;
  41. else if ( type === 'vec4' ) return 3;
  42. return 0;
  43. }
  44. createDataFromNode( node, shaderStage = null ) {
  45. let nodeData = this.nodesData.get( node );
  46. if ( nodeData === undefined ) {
  47. nodeData = { vertex: {}, fragment: {} };
  48. this.nodesData.set( node, nodeData );
  49. }
  50. return shaderStage ? nodeData[ shaderStage ] : nodeData;
  51. }
  52. createUniformFromNode( node, shaderStage, type ) {
  53. const nodeData = this.createDataFromNode( node, shaderStage );
  54. let nodeUniform = nodeData.uniform;
  55. if ( nodeUniform === undefined ) {
  56. const uniforms = this.uniforms[shaderStage];
  57. const index = uniforms.length;
  58. nodeUniform = new NodeUniform( 'nodeU' + index, type, node );
  59. uniforms.push( nodeUniform );
  60. nodeData.uniform = nodeUniform;
  61. }
  62. return nodeUniform;
  63. }
  64. /*
  65. analyzeNode( node ) {
  66. }
  67. */
  68. flowNode( node, output ) {
  69. let flowData = {};
  70. flowData.result = node.build( this, output );
  71. return flowData;
  72. }
  73. buildDefines( shader ) {
  74. const defines = this.defines[ shader ];
  75. let code = '';
  76. for ( let name in defines ) {
  77. code += `#define ${name} ${defines[name]}\n`;
  78. }
  79. return code;
  80. }
  81. build( shaderStage ) {
  82. this.setShaderStage( shaderStage );
  83. const slots = this.slots[ shaderStage ];
  84. const uniforms = this.uniforms[ shaderStage ];
  85. if ( slots.length ) {
  86. this.addDefine( shaderStage, 'NODE', VERSION );
  87. for( let i = 0; i < slots.length; i++) {
  88. let slot = slots[i];
  89. let flowData = this.flowNode( slot.node, slot.output );
  90. this.addDefine( shaderStage, `NODE_${slot.name}`, flowData.result );
  91. }
  92. let uniformsCode = '';
  93. for( let i = 0; i < uniforms.length; i++) {
  94. let uniform = uniforms[i];
  95. uniformsCode += `${uniform.type} ${uniform.name}; `;
  96. }
  97. this.addDefine( shaderStage, 'NODE_UNIFORMS', uniformsCode );
  98. }
  99. let defines = this.buildDefines( shaderStage );
  100. return {
  101. defines
  102. };
  103. }
  104. format( code, fromType, toType ) {
  105. const typeToType = `${fromType} -> ${toType}`;
  106. console.log( typeToType );
  107. switch ( typeToType ) {
  108. case 'float -> vec3' : return `vec3( ${code} )`;
  109. case 'vec3 -> float' : return `${code}.x`;
  110. }
  111. return code;
  112. }
  113. }
  114. export default NodeBuilder;