2
0

NodeMaterial.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. /**
  2. * @author sunag / http://www.sunag.com.br/
  3. */
  4. THREE.NodeMaterial = function( vertex, fragment ) {
  5. THREE.ShaderMaterial.call( this );
  6. this.vertex = vertex || new THREE.RawNode( new THREE.PositionNode( THREE.PositionNode.PROJECTION ) );
  7. this.fragment = fragment || new THREE.RawNode( new THREE.ColorNode( 0xFF0000 ) );
  8. };
  9. THREE.NodeMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
  10. THREE.NodeMaterial.prototype.constructor = THREE.NodeMaterial;
  11. THREE.NodeMaterial.Type = {
  12. t : 'sampler2D',
  13. tc : 'samplerCube',
  14. bv1 : 'bool',
  15. iv1 : 'int',
  16. fv1 : 'float',
  17. c : 'vec3',
  18. v2 : 'vec2',
  19. v3 : 'vec3',
  20. v4 : 'vec4'
  21. };
  22. THREE.NodeMaterial.GetShortcuts = function( prop, name ) {
  23. return {
  24. get: function() {
  25. return this[ prop ][ name ];
  26. },
  27. set: function( val ) {
  28. this[ prop ][ name ] = val;
  29. }
  30. };
  31. };
  32. THREE.NodeMaterial.Shortcuts = function( proto, prop, list ) {
  33. var shortcuts = {};
  34. for ( var i = 0; i < list.length; ++ i ) {
  35. var name = list[ i ];
  36. shortcuts[ name ] = this.GetShortcuts( prop, name );
  37. }
  38. Object.defineProperties( proto, shortcuts );
  39. };
  40. THREE.NodeMaterial.prototype.updateAnimation = function( delta ) {
  41. for ( var i = 0; i < this.requestUpdate.length; ++ i ) {
  42. this.requestUpdate[ i ].updateAnimation( delta );
  43. }
  44. };
  45. THREE.NodeMaterial.prototype.build = function() {
  46. var vertex, fragment;
  47. this.defines = {};
  48. this.uniforms = {};
  49. this.nodeData = {};
  50. this.vertexUniform = [];
  51. this.fragmentUniform = [];
  52. this.vertexTemps = [];
  53. this.fragmentTemps = [];
  54. this.uniformList = [];
  55. this.consts = [];
  56. this.functions = [];
  57. this.requestUpdate = [];
  58. this.requestAttrib = {
  59. uv: [],
  60. color: []
  61. };
  62. this.vertexPars = '';
  63. this.fragmentPars = '';
  64. this.vertexCode = '';
  65. this.fragmentCode = '';
  66. this.vertexNode = '';
  67. this.fragmentNode = '';
  68. var builder = new THREE.BuilderNode( this );
  69. vertex = this.vertex.build( builder.setShader( 'vertex' ), 'v4' );
  70. fragment = this.fragment.build( builder.setShader( 'fragment' ), 'v4' );
  71. if ( this.requestAttrib.uv[ 0 ] ) {
  72. this.addVertexPars( 'varying vec2 vUv;' );
  73. this.addFragmentPars( 'varying vec2 vUv;' );
  74. this.addVertexCode( 'vUv = uv;' );
  75. }
  76. if ( this.requestAttrib.uv[ 1 ] ) {
  77. this.addVertexPars( 'varying vec2 vUv2; attribute vec2 uv2;' );
  78. this.addFragmentPars( 'varying vec2 vUv2;' );
  79. this.addVertexCode( 'vUv2 = uv2;' );
  80. }
  81. if ( this.requestAttrib.color[ 0 ] ) {
  82. this.addVertexPars( 'varying vec4 vColor; attribute vec4 color;' );
  83. this.addFragmentPars( 'varying vec4 vColor;' );
  84. this.addVertexCode( 'vColor = color;' );
  85. }
  86. if ( this.requestAttrib.color[ 1 ] ) {
  87. this.addVertexPars( 'varying vec4 vColor2; attribute vec4 color2;' );
  88. this.addFragmentPars( 'varying vec4 vColor2;' );
  89. this.addVertexCode( 'vColor2 = color2;' );
  90. }
  91. if ( this.requestAttrib.position ) {
  92. this.addVertexPars( 'varying vec3 vPosition;' );
  93. this.addFragmentPars( 'varying vec3 vPosition;' );
  94. this.addVertexCode( 'vPosition = transformed;' );
  95. }
  96. if ( this.requestAttrib.worldPosition ) {
  97. // for future update replace from the native "varying vec3 vWorldPosition" for optimization
  98. this.addVertexPars( 'varying vec3 vWPosition;' );
  99. this.addFragmentPars( 'varying vec3 vWPosition;' );
  100. this.addVertexCode( 'vWPosition = worldPosition.xyz;' );
  101. }
  102. if ( this.requestAttrib.normal ) {
  103. this.addVertexPars( 'varying vec3 vObjectNormal;' );
  104. this.addFragmentPars( 'varying vec3 vObjectNormal;' );
  105. this.addVertexCode( 'vObjectNormal = normal;' );
  106. }
  107. if ( this.requestAttrib.worldNormal ) {
  108. this.addVertexPars( 'varying vec3 vWNormal;' );
  109. this.addFragmentPars( 'varying vec3 vWNormal;' );
  110. this.addVertexCode( 'vWNormal = ( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz;' );
  111. }
  112. this.lights = this.requestAttrib.light;
  113. this.transparent = this.requestAttrib.transparent;
  114. this.vertexShader = [
  115. this.vertexPars,
  116. this.getCodePars( this.vertexUniform, 'uniform' ),
  117. this.getIncludes( this.consts[ 'vertex' ] ),
  118. this.getIncludes( this.functions[ 'vertex' ] ),
  119. 'void main(){',
  120. this.getCodePars( this.vertexTemps ),
  121. vertex,
  122. this.vertexCode,
  123. '}'
  124. ].join( "\n" );
  125. this.fragmentShader = [
  126. this.fragmentPars,
  127. this.getCodePars( this.fragmentUniform, 'uniform' ),
  128. this.getIncludes( this.consts[ 'fragment' ] ),
  129. this.getIncludes( this.functions[ 'fragment' ] ),
  130. 'void main(){',
  131. this.getCodePars( this.fragmentTemps ),
  132. this.fragmentCode,
  133. fragment,
  134. '}'
  135. ].join( "\n" );
  136. this.needsUpdate = true;
  137. this.dispose(); // force update
  138. return this;
  139. };
  140. THREE.NodeMaterial.prototype.define = function( name, value ) {
  141. this.defines[ name ] = value == undefined ? 1 : value;
  142. };
  143. THREE.NodeMaterial.prototype.isDefined = function( name ) {
  144. return this.defines[ name ] != undefined;
  145. };
  146. THREE.NodeMaterial.prototype.mergeUniform = function( uniforms ) {
  147. for ( var name in uniforms ) {
  148. this.uniforms[ name ] = uniforms[ name ];
  149. }
  150. };
  151. THREE.NodeMaterial.prototype.createUniform = function( value, type, ns, needsUpdate ) {
  152. var index = this.uniformList.length;
  153. var uniform = {
  154. type : type,
  155. value : value,
  156. name : ns ? ns : 'nVu' + index,
  157. needsUpdate : needsUpdate
  158. };
  159. this.uniformList.push( uniform );
  160. return uniform;
  161. };
  162. THREE.NodeMaterial.prototype.getVertexTemp = function( uuid, type, ns ) {
  163. if ( ! this.vertexTemps[ uuid ] ) {
  164. var index = this.vertexTemps.length,
  165. name = ns ? ns : 'nVt' + index,
  166. data = { name : name, type : type };
  167. this.vertexTemps.push( data );
  168. this.vertexTemps[ uuid ] = data;
  169. }
  170. return this.vertexTemps[ uuid ];
  171. };
  172. THREE.NodeMaterial.prototype.getFragmentTemp = function( uuid, type, ns ) {
  173. if ( ! this.fragmentTemps[ uuid ] ) {
  174. var index = this.fragmentTemps.length,
  175. name = ns ? ns : 'nVt' + index,
  176. data = { name : name, type : type };
  177. this.fragmentTemps.push( data );
  178. this.fragmentTemps[ uuid ] = data;
  179. }
  180. return this.fragmentTemps[ uuid ];
  181. };
  182. THREE.NodeMaterial.prototype.getIncludes = function( incs ) {
  183. function sortByPosition( a, b ) {
  184. return b.deps - a.deps;
  185. }
  186. return function( incs ) {
  187. if ( ! incs ) return '';
  188. var code = '';
  189. var incs = incs.sort( sortByPosition );
  190. for ( var i = 0; i < incs.length; i ++ ) {
  191. code += incs[ i ].node.src + '\n';
  192. }
  193. return code;
  194. }
  195. }();
  196. THREE.NodeMaterial.prototype.addVertexPars = function( code ) {
  197. this.vertexPars += code + '\n';
  198. };
  199. THREE.NodeMaterial.prototype.addFragmentPars = function( code ) {
  200. this.fragmentPars += code + '\n';
  201. };
  202. THREE.NodeMaterial.prototype.addVertexCode = function( code ) {
  203. this.vertexCode += code + '\n';
  204. };
  205. THREE.NodeMaterial.prototype.addFragmentCode = function( code ) {
  206. this.fragmentCode += code + '\n';
  207. };
  208. THREE.NodeMaterial.prototype.addVertexNode = function( code ) {
  209. this.vertexNode += code + '\n';
  210. };
  211. THREE.NodeMaterial.prototype.clearVertexNode = function() {
  212. var code = this.fragmentNode;
  213. this.fragmentNode = '';
  214. return code;
  215. };
  216. THREE.NodeMaterial.prototype.addFragmentNode = function( code ) {
  217. this.fragmentNode += code + '\n';
  218. };
  219. THREE.NodeMaterial.prototype.clearFragmentNode = function() {
  220. var code = this.fragmentNode;
  221. this.fragmentNode = '';
  222. return code;
  223. };
  224. THREE.NodeMaterial.prototype.getCodePars = function( pars, prefix ) {
  225. prefix = prefix || '';
  226. var code = '';
  227. for ( var i = 0, l = pars.length; i < l; ++ i ) {
  228. var parsType = pars[ i ].type;
  229. var parsName = pars[ i ].name;
  230. var parsValue = pars[ i ].value;
  231. if ( parsType == 't' && parsValue instanceof THREE.CubeTexture ) parsType = 'tc';
  232. var type = THREE.NodeMaterial.Type[ parsType ];
  233. if ( type == undefined ) throw new Error( "Node pars " + parsType + " not found." );
  234. code += prefix + ' ' + type + ' ' + parsName + ';\n';
  235. }
  236. return code;
  237. };
  238. THREE.NodeMaterial.prototype.getVertexUniform = function( value, type, ns, needsUpdate ) {
  239. var uniform = this.createUniform( value, type, ns, needsUpdate );
  240. this.vertexUniform.push( uniform );
  241. this.vertexUniform[ uniform.name ] = uniform;
  242. this.uniforms[ uniform.name ] = uniform;
  243. return uniform;
  244. };
  245. THREE.NodeMaterial.prototype.getFragmentUniform = function( value, type, ns, needsUpdate ) {
  246. var uniform = this.createUniform( value, type, ns, needsUpdate );
  247. this.fragmentUniform.push( uniform );
  248. this.fragmentUniform[ uniform.name ] = uniform;
  249. this.uniforms[ uniform.name ] = uniform;
  250. return uniform;
  251. };
  252. THREE.NodeMaterial.prototype.getDataNode = function( uuid ) {
  253. return this.nodeData[ uuid ] = this.nodeData[ uuid ] || {};
  254. };
  255. THREE.NodeMaterial.prototype.include = function( shader, node ) {
  256. var includes;
  257. node = typeof node === 'string' ? THREE.LibNode.get( node ) : node;
  258. if ( node instanceof THREE.FunctionNode ) {
  259. for ( var i = 0; i < node.includes.length; i ++ ) {
  260. this.include( shader, node.includes[ i ] );
  261. }
  262. includes = this.functions[ shader ] = this.functions[ shader ] || [];
  263. }
  264. else if ( node instanceof THREE.ConstNode ) {
  265. includes = this.consts[ shader ] = this.consts[ shader ] || [];
  266. }
  267. if ( includes[ node.name ] === undefined ) {
  268. for ( var ext in node.extensions ) {
  269. this.extensions[ ext ] = true;
  270. }
  271. includes[ node.name ] = {
  272. node : node,
  273. deps : 1
  274. };
  275. includes.push( includes[ node.name ] );
  276. }
  277. else ++ includes[ node.name ].deps;
  278. };