2
0

NodeMaterial.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. /**
  2. * @author sunag / http://www.sunag.com.br/
  3. */
  4. THREE.NodeMaterial = function ( vertex, fragment ) {
  5. THREE.ShaderMaterial.call( this );
  6. this.defines.UUID = this.uuid;
  7. this.vertex = vertex || new THREE.RawNode( new THREE.PositionNode( THREE.PositionNode.PROJECTION ) );
  8. this.fragment = fragment || new THREE.RawNode( new THREE.ColorNode( 0xFF0000 ) );
  9. this.updaters = [];
  10. };
  11. THREE.NodeMaterial.types = {
  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. m3: 'mat3',
  22. m4: 'mat4'
  23. };
  24. THREE.NodeMaterial.addShortcuts = function () {
  25. function applyShortcut( proxy, property, subProperty ) {
  26. if ( subProperty ) {
  27. return {
  28. get: function () {
  29. return this[ proxy ][ property ][ subProperty ];
  30. },
  31. set: function ( val ) {
  32. this[ proxy ][ property ][ subProperty ] = val;
  33. }
  34. };
  35. } else {
  36. return {
  37. get: function () {
  38. return this[ proxy ][ property ];
  39. },
  40. set: function ( val ) {
  41. this[ proxy ][ property ] = val;
  42. }
  43. };
  44. }
  45. }
  46. return function addShortcuts( proto, proxy, list ) {
  47. var shortcuts = {};
  48. for ( var i = 0; i < list.length; ++ i ) {
  49. var data = list[ i ].split( "." ),
  50. property = data[0],
  51. subProperty = data[1];
  52. shortcuts[ property ] = applyShortcut( proxy, property, subProperty );
  53. }
  54. Object.defineProperties( proto, shortcuts );
  55. };
  56. }();
  57. THREE.NodeMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
  58. THREE.NodeMaterial.prototype.constructor = THREE.NodeMaterial;
  59. THREE.NodeMaterial.prototype.type = "NodeMaterial";
  60. THREE.NodeMaterial.prototype.isNodeMaterial = true;
  61. THREE.NodeMaterial.prototype.updateFrame = function ( frame ) {
  62. for ( var i = 0; i < this.updaters.length; ++ i ) {
  63. frame.updateNode( this.updaters[ i ] );
  64. }
  65. };
  66. THREE.NodeMaterial.prototype.onBeforeCompile = function ( shader, renderer ) {
  67. if ( this.needsUpdate ) {
  68. this.build( { dispose: false, renderer: renderer } );
  69. shader.uniforms = this.uniforms;
  70. shader.vertexShader = this.vertexShader;
  71. shader.fragmentShader = this.fragmentShader;
  72. }
  73. };
  74. THREE.NodeMaterial.prototype.build = function ( params ) {
  75. params = params || {};
  76. params.dispose = params.dispose !== undefined ? params.dispose : true;
  77. var vertex, fragment;
  78. this.nodes = [];
  79. this.defines = { UUID: this.uuid };
  80. this.uniforms = {};
  81. this.attributes = {};
  82. this.extensions = {};
  83. this.nodeData = {};
  84. this.vertexUniform = [];
  85. this.fragmentUniform = [];
  86. this.vars = [];
  87. this.vertexTemps = [];
  88. this.fragmentTemps = [];
  89. this.uniformList = [];
  90. this.consts = [];
  91. this.functions = [];
  92. this.structs = [];
  93. this.updaters = [];
  94. this.requires = {
  95. uv: [],
  96. color: [],
  97. lights: this.lights,
  98. fog: this.fog
  99. };
  100. this.vertexPars = '';
  101. this.fragmentPars = '';
  102. this.vertexCode = '';
  103. this.fragmentCode = '';
  104. this.vertexNode = '';
  105. this.fragmentNode = '';
  106. this.prefixCode = [
  107. "#ifdef GL_EXT_shader_texture_lod",
  108. " #define texCube(a, b) textureCube(a, b)",
  109. " #define texCubeBias(a, b, c) textureCubeLodEXT(a, b, c)",
  110. " #define tex2D(a, b) texture2D(a, b)",
  111. " #define tex2DBias(a, b, c) texture2DLodEXT(a, b, c)",
  112. "#else",
  113. " #define texCube(a, b) textureCube(a, b)",
  114. " #define texCubeBias(a, b, c) textureCube(a, b, c)",
  115. " #define tex2D(a, b) texture2D(a, b)",
  116. " #define tex2DBias(a, b, c) texture2D(a, b, c)",
  117. "#endif",
  118. "#include <packing>"
  119. ].join( "\n" );
  120. var builder = new THREE.NodeBuilder( this, params.renderer );
  121. vertex = this.vertex.build( builder.setShader( 'vertex' ), 'v4' );
  122. fragment = this.fragment.build( builder.setShader( 'fragment' ), 'v4' );
  123. if ( this.requires.uv[ 0 ] ) {
  124. this.addVertexPars( 'varying vec2 vUv;' );
  125. this.addFragmentPars( 'varying vec2 vUv;' );
  126. this.addVertexCode( 'vUv = uv;' );
  127. }
  128. if ( this.requires.uv[ 1 ] ) {
  129. this.addVertexPars( 'varying vec2 vUv2; attribute vec2 uv2;' );
  130. this.addFragmentPars( 'varying vec2 vUv2;' );
  131. this.addVertexCode( 'vUv2 = uv2;' );
  132. }
  133. if ( this.requires.color[ 0 ] ) {
  134. this.addVertexPars( 'varying vec4 vColor; attribute vec4 color;' );
  135. this.addFragmentPars( 'varying vec4 vColor;' );
  136. this.addVertexCode( 'vColor = color;' );
  137. }
  138. if ( this.requires.color[ 1 ] ) {
  139. this.addVertexPars( 'varying vec4 vColor2; attribute vec4 color2;' );
  140. this.addFragmentPars( 'varying vec4 vColor2;' );
  141. this.addVertexCode( 'vColor2 = color2;' );
  142. }
  143. if ( this.requires.position ) {
  144. this.addVertexPars( 'varying vec3 vPosition;' );
  145. this.addFragmentPars( 'varying vec3 vPosition;' );
  146. this.addVertexCode( 'vPosition = transformed;' );
  147. }
  148. if ( this.requires.worldPosition ) {
  149. this.addVertexPars( 'varying vec3 vWPosition;' );
  150. this.addFragmentPars( 'varying vec3 vWPosition;' );
  151. this.addVertexCode( 'vWPosition = ( modelMatrix * vec4( transformed, 1.0 ) ).xyz;' );
  152. }
  153. if ( this.requires.normal ) {
  154. this.addVertexPars( 'varying vec3 vObjectNormal;' );
  155. this.addFragmentPars( 'varying vec3 vObjectNormal;' );
  156. this.addVertexCode( 'vObjectNormal = normal;' );
  157. }
  158. if ( this.requires.worldNormal ) {
  159. this.addVertexPars( 'varying vec3 vWNormal;' );
  160. this.addFragmentPars( 'varying vec3 vWNormal;' );
  161. this.addVertexCode( 'vWNormal = ( modelMatrix * vec4( objectNormal, 0.0 ) ).xyz;' );
  162. }
  163. this.fog = this.requires.fog;
  164. this.lights = this.requires.lights;
  165. this.transparent = this.requires.transparent || this.blending > THREE.NormalBlending;
  166. this.vertexShader = [
  167. this.prefixCode,
  168. this.vertexPars,
  169. this.getCodePars( this.vertexUniform, 'uniform' ),
  170. this.getIncludes( this.consts[ 'vertex' ] ),
  171. this.getIncludes( this.structs[ 'vertex' ] ),
  172. this.getIncludes( this.functions[ 'vertex' ] ),
  173. 'void main() {',
  174. this.getCodePars( this.vertexTemps ),
  175. vertex,
  176. this.vertexCode,
  177. '}'
  178. ].join( "\n" );
  179. this.fragmentShader = [
  180. this.prefixCode,
  181. this.fragmentPars,
  182. this.getCodePars( this.fragmentUniform, 'uniform' ),
  183. this.getIncludes( this.consts[ 'fragment' ] ),
  184. this.getIncludes( this.structs[ 'fragment' ] ),
  185. this.getIncludes( this.functions[ 'fragment' ] ),
  186. 'void main() {',
  187. this.getCodePars( this.fragmentTemps ),
  188. this.fragmentCode,
  189. fragment,
  190. '}'
  191. ].join( "\n" );
  192. if ( params.dispose ) {
  193. // force update
  194. this.dispose();
  195. }
  196. return this;
  197. };
  198. THREE.NodeMaterial.prototype.define = function ( name, value ) {
  199. this.defines[ name ] = value == undefined ? 1 : value;
  200. };
  201. THREE.NodeMaterial.prototype.isDefined = function ( name ) {
  202. return this.defines[ name ] != undefined;
  203. };
  204. THREE.NodeMaterial.prototype.mergeUniform = function ( uniforms ) {
  205. for ( var name in uniforms ) {
  206. this.uniforms[ name ] = uniforms[ name ];
  207. }
  208. };
  209. THREE.NodeMaterial.prototype.createUniform = function ( type, node, ns, needsUpdate ) {
  210. var index = this.uniformList.length;
  211. var uniform = new THREE.NodeUniform( {
  212. type: type,
  213. name: ns ? ns : 'nVu' + index + '_' + THREE.Math.generateUUID().substr(0, 8),
  214. node: node,
  215. needsUpdate: needsUpdate
  216. } );
  217. this.uniformList.push( uniform );
  218. return uniform;
  219. };
  220. THREE.NodeMaterial.prototype.getVertexTemp = function ( uuid, type, ns ) {
  221. var data = this.vertexTemps[ uuid ];
  222. if ( ! data ) {
  223. var index = this.vertexTemps.length,
  224. name = ns ? ns : 'nVt' + index;
  225. data = { name: name, type: type };
  226. this.vertexTemps.push( data );
  227. this.vertexTemps[ uuid ] = data;
  228. }
  229. return data;
  230. };
  231. THREE.NodeMaterial.prototype.getFragmentTemp = function ( uuid, type, ns ) {
  232. var data = this.fragmentTemps[ uuid ];
  233. if ( ! data ) {
  234. var index = this.fragmentTemps.length,
  235. name = ns ? ns : 'nVt' + index;
  236. data = { name: name, type: type };
  237. this.fragmentTemps.push( data );
  238. this.fragmentTemps[ uuid ] = data;
  239. }
  240. return data;
  241. };
  242. THREE.NodeMaterial.prototype.getVar = function ( uuid, type, ns ) {
  243. var data = this.vars[ uuid ];
  244. if ( ! data ) {
  245. var index = this.vars.length,
  246. name = ns ? ns : 'nVv' + index;
  247. data = { name: name, type: type };
  248. this.vars.push( data );
  249. this.vars[ uuid ] = data;
  250. this.addVertexPars( 'varying ' + type + ' ' + name + ';' );
  251. this.addFragmentPars( 'varying ' + type + ' ' + name + ';' );
  252. }
  253. return data;
  254. };
  255. THREE.NodeMaterial.prototype.getAttribute = function ( name, type ) {
  256. if ( ! this.attributes[ name ] ) {
  257. var varying = this.getVar( name, type );
  258. this.addVertexPars( 'attribute ' + type + ' ' + name + ';' );
  259. this.addVertexCode( varying.name + ' = ' + name + ';' );
  260. this.attributes[ name ] = { varying: varying, name: name, type: type };
  261. }
  262. return this.attributes[ name ];
  263. };
  264. THREE.NodeMaterial.prototype.getIncludes = function () {
  265. function sortByPosition( a, b ) {
  266. return a.deps.length - b.deps.length;
  267. }
  268. return function ( incs ) {
  269. if ( ! incs ) return '';
  270. var code = '', incs = incs.sort( sortByPosition );
  271. for ( var i = 0; i < incs.length; i ++ ) {
  272. if ( incs[ i ].src ) code += incs[ i ].src + '\n';
  273. }
  274. return code;
  275. };
  276. }();
  277. THREE.NodeMaterial.prototype.addVertexPars = function ( code ) {
  278. this.vertexPars += code + '\n';
  279. };
  280. THREE.NodeMaterial.prototype.addFragmentPars = function ( code ) {
  281. this.fragmentPars += code + '\n';
  282. };
  283. THREE.NodeMaterial.prototype.addVertexCode = function ( code ) {
  284. this.vertexCode += code + '\n';
  285. };
  286. THREE.NodeMaterial.prototype.addFragmentCode = function ( code ) {
  287. this.fragmentCode += code + '\n';
  288. };
  289. THREE.NodeMaterial.prototype.addVertexNode = function ( code ) {
  290. this.vertexNode += code + '\n';
  291. };
  292. THREE.NodeMaterial.prototype.clearVertexNode = function () {
  293. var code = this.vertexNode;
  294. this.vertexNode = '';
  295. return code;
  296. };
  297. THREE.NodeMaterial.prototype.addFragmentNode = function ( code ) {
  298. this.fragmentNode += code + '\n';
  299. };
  300. THREE.NodeMaterial.prototype.clearFragmentNode = function () {
  301. var code = this.fragmentNode;
  302. this.fragmentNode = '';
  303. return code;
  304. };
  305. THREE.NodeMaterial.prototype.getCodePars = function ( pars, prefix ) {
  306. prefix = prefix || '';
  307. var code = '';
  308. for ( var i = 0, l = pars.length; i < l; ++ i ) {
  309. var parsType = pars[ i ].type;
  310. var parsName = pars[ i ].name;
  311. var parsValue = pars[ i ].value;
  312. if ( parsType === 't' && parsValue instanceof THREE.CubeTexture ) parsType = 'tc';
  313. var type = THREE.NodeMaterial.types[ parsType ] || parsType;
  314. if ( type === undefined ) throw new Error( "Node pars " + parsType + " not found." );
  315. code += prefix + ' ' + type + ' ' + parsName + ';\n';
  316. }
  317. return code;
  318. };
  319. THREE.NodeMaterial.prototype.createVertexUniform = function ( type, node, ns, needsUpdate ) {
  320. var uniform = this.createUniform( type, node, ns, needsUpdate );
  321. this.vertexUniform.push( uniform );
  322. this.vertexUniform[ uniform.name ] = uniform;
  323. this.uniforms[ uniform.name ] = uniform;
  324. return uniform;
  325. };
  326. THREE.NodeMaterial.prototype.createFragmentUniform = function ( type, node, ns, needsUpdate ) {
  327. var uniform = this.createUniform( type, node, ns, needsUpdate );
  328. this.fragmentUniform.push( uniform );
  329. this.fragmentUniform[ uniform.name ] = uniform;
  330. this.uniforms[ uniform.name ] = uniform;
  331. return uniform;
  332. };
  333. THREE.NodeMaterial.prototype.getDataNode = function ( uuid ) {
  334. return this.nodeData[ uuid ] = this.nodeData[ uuid ] || {};
  335. };
  336. THREE.NodeMaterial.prototype.include = function ( builder, node, parent, source ) {
  337. var includes;
  338. node = typeof node === 'string' ? THREE.NodeLib.get( node ) : node;
  339. if ( node instanceof THREE.FunctionNode ) {
  340. includes = this.functions[ builder.shader ] = this.functions[ builder.shader ] || [];
  341. } else if ( node instanceof THREE.ConstNode ) {
  342. includes = this.consts[ builder.shader ] = this.consts[ builder.shader ] || [];
  343. } else if ( node instanceof THREE.StructNode ) {
  344. includes = this.structs[ builder.shader ] = this.structs[ builder.shader ] || [];
  345. }
  346. if (node) {
  347. var included = includes[ node.name ];
  348. if ( ! included ) {
  349. included = includes[ node.name ] = {
  350. node: node,
  351. deps: []
  352. };
  353. includes.push( included );
  354. included.src = node.build( builder, 'source' );
  355. }
  356. if ( node instanceof THREE.FunctionNode && parent && includes[ parent.name ] && includes[ parent.name ].deps.indexOf( node ) == - 1 ) {
  357. includes[ parent.name ].deps.push( node );
  358. if ( node.includes && node.includes.length ) {
  359. var i = 0;
  360. do {
  361. this.include( builder, node.includes[ i ++ ], parent );
  362. } while ( i < node.includes.length );
  363. }
  364. }
  365. if ( source ) {
  366. included.src = source;
  367. }
  368. } else {
  369. throw new Error("Include not found.");
  370. }
  371. };
  372. THREE.NodeMaterial.prototype.copy = function ( source ) {
  373. var uuid = this.uuid;
  374. for (var name in source) {
  375. this[name] = source[name];
  376. }
  377. this.uuid = uuid;
  378. if ( source.userData !== undefined) {
  379. this.userData = JSON.parse( JSON.stringify( source.userData ) );
  380. }
  381. };
  382. THREE.NodeMaterial.prototype.toJSON = function ( meta ) {
  383. var isRootObject = ( meta === undefined || typeof meta === 'string' );
  384. if ( isRootObject ) {
  385. meta = {
  386. nodes: {}
  387. };
  388. }
  389. if ( meta && ! meta.materials ) meta.materials = {};
  390. if ( ! meta.materials[ this.uuid ] ) {
  391. var data = {};
  392. data.uuid = this.uuid;
  393. data.type = this.type;
  394. meta.materials[ data.uuid ] = data;
  395. if ( this.name !== "" ) data.name = this.name;
  396. if ( this.size !== undefined ) data.size = this.size;
  397. if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
  398. if ( this.blending !== THREE.NormalBlending ) data.blending = this.blending;
  399. if ( this.flatShading === true ) data.flatShading = this.flatShading;
  400. if ( this.side !== THREE.FrontSide ) data.side = this.side;
  401. if ( this.vertexColors !== THREE.NoColors ) data.vertexColors = this.vertexColors;
  402. if ( this.depthFunc !== THREE.LessEqualDepth ) data.depthFunc = this.depthFunc;
  403. if ( this.depthTest === false ) data.depthTest = this.depthTest;
  404. if ( this.depthWrite === false ) data.depthWrite = this.depthWrite;
  405. if ( this.linewidth !== 1 ) data.linewidth = this.linewidth;
  406. if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
  407. if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
  408. if ( this.scale !== undefined ) data.scale = this.scale;
  409. if ( this.dithering === true ) data.dithering = true;
  410. if ( this.wireframe === true ) data.wireframe = this.wireframe;
  411. if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
  412. if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
  413. if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
  414. if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
  415. if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha;
  416. if ( this.morphTargets === true ) data.morphTargets = true;
  417. if ( this.skinning === true ) data.skinning = true;
  418. if ( this.visible === false ) data.visible = false;
  419. if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
  420. data.fog = this.fog;
  421. data.lights = this.lights;
  422. data.vertex = this.vertex.toJSON( meta ).uuid;
  423. data.fragment = this.fragment.toJSON( meta ).uuid;
  424. }
  425. meta.material = this.uuid;
  426. return meta;
  427. };