NodeBuilder.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /**
  2. * @author sunag / http://www.sunag.com.br/
  3. */
  4. THREE.NodeBuilder = function ( material, renderer ) {
  5. this.material = material;
  6. this.renderer = renderer;
  7. this.caches = [];
  8. this.slots = [];
  9. this.keywords = {};
  10. this.parsing = false;
  11. this.optimize = true;
  12. this.update();
  13. };
  14. THREE.NodeBuilder.type = {
  15. float: 'fv1',
  16. vec2: 'v2',
  17. vec3: 'v3',
  18. vec4: 'v4',
  19. mat4: 'v4',
  20. int: 'iv1'
  21. };
  22. THREE.NodeBuilder.constructors = [
  23. 'float',
  24. 'vec2',
  25. 'vec3',
  26. 'vec4'
  27. ];
  28. THREE.NodeBuilder.elements = [
  29. 'x',
  30. 'y',
  31. 'z',
  32. 'w'
  33. ];
  34. THREE.NodeBuilder.prototype = {
  35. constructor: THREE.NodeBuilder,
  36. addCache: function ( name, requires ) {
  37. this.caches.push( {
  38. name: name || '',
  39. requires: requires || {}
  40. } );
  41. return this.update();
  42. },
  43. removeCache: function () {
  44. this.caches.pop();
  45. return this.update();
  46. },
  47. addSlot: function ( name ) {
  48. this.slots.push( {
  49. name: name || ''
  50. } );
  51. return this.update();
  52. },
  53. removeSlot: function () {
  54. this.slots.pop();
  55. return this.update();
  56. },
  57. isCache: function ( name ) {
  58. var i = this.caches.length;
  59. while ( i -- ) {
  60. if ( this.caches[ i ].name == name ) return true;
  61. }
  62. return false;
  63. },
  64. isSlot: function ( name ) {
  65. var i = this.slots.length;
  66. while ( i -- ) {
  67. if ( this.slots[ i ].name == name ) return true;
  68. }
  69. return false;
  70. },
  71. update: function () {
  72. var cache = this.caches[ this.caches.length - 1 ];
  73. var slot = this.slots[ this.slots.length - 1 ];
  74. this.slot = slot ? slot.name : '';
  75. this.cache = cache ? cache.name : '';
  76. this.requires = cache ? cache.requires : {};
  77. return this;
  78. },
  79. require: function ( name, node ) {
  80. this.requires[ name ] = node;
  81. return this;
  82. },
  83. include: function ( node, parent, source ) {
  84. this.material.include( this, node, parent, source );
  85. return this;
  86. },
  87. colorToVector: function ( color ) {
  88. return color.replace( 'r', 'x' ).replace( 'g', 'y' ).replace( 'b', 'z' ).replace( 'a', 'w' );
  89. },
  90. getConstructorFromLength: function ( len ) {
  91. return THREE.NodeBuilder.constructors[ len - 1 ];
  92. },
  93. getFormatName: function ( format ) {
  94. return format.replace( /c/g, 'v3' ).replace( /fv1/g, 'v1' ).replace( /iv1/g, 'i' );
  95. },
  96. isFormatMatrix: function ( format ) {
  97. return /^m/.test( format );
  98. },
  99. getFormatLength: function ( format ) {
  100. return parseInt( this.getFormatName( format ).substr( 1 ) );
  101. },
  102. getFormatFromLength: function ( len ) {
  103. if ( len == 1 ) return 'fv1';
  104. return 'v' + len;
  105. },
  106. resolve: function() {
  107. for(var i = 0; i < arguments.length; i++) {
  108. var nodeCandidate = arguments[i];
  109. if (nodeCandidate !== undefined) {
  110. if (nodeCandidate.isNode) {
  111. return nodeCandidate;
  112. } else if (nodeCandidate.isTexture) {
  113. switch( nodeCandidate.mapping ) {
  114. case THREE.CubeReflectionMapping:
  115. case THREE.CubeRefractionMapping:
  116. return new THREE.CubeTextureNode( nodeCandidate );
  117. break;
  118. case THREE.CubeUVReflectionMapping:
  119. case THREE.CubeUVRefractionMapping:
  120. return new THREE.TextureCubeNode( new THREE.TextureNode( nodeCandidate ) );
  121. break;
  122. default:
  123. return new THREE.TextureNode( nodeCandidate );
  124. }
  125. } else if (nodeCandidate.isVector2) {
  126. return new THREE.Vector2Node( nodeCandidate );
  127. } else if (nodeCandidate.isVector3) {
  128. return new THREE.Vector3Node( nodeCandidate );
  129. } else if (nodeCandidate.isVector4) {
  130. return new THREE.Vector4Node( nodeCandidate );
  131. }
  132. }
  133. }
  134. },
  135. format: function ( code, from, to ) {
  136. var format = this.getFormatName( to + ' = ' + from );
  137. switch ( format ) {
  138. case 'v1 = v2': return code + '.x';
  139. case 'v1 = v3': return code + '.x';
  140. case 'v1 = v4': return code + '.x';
  141. case 'v1 = i': return 'float( ' + code + ' )';
  142. case 'v2 = v1': return 'vec2( ' + code + ' )';
  143. case 'v2 = v3': return code + '.xy';
  144. case 'v2 = v4': return code + '.xy';
  145. case 'v2 = i': return 'vec2( float( ' + code + ' ) )';
  146. case 'v3 = v1': return 'vec3( ' + code + ' )';
  147. case 'v3 = v2': return 'vec3( ' + code + ', 0.0 )';
  148. case 'v3 = v4': return code + '.xyz';
  149. case 'v3 = i': return 'vec2( float( ' + code + ' ) )';
  150. case 'v4 = v1': return 'vec4( ' + code + ' )';
  151. case 'v4 = v2': return 'vec4( ' + code + ', 0.0, 1.0 )';
  152. case 'v4 = v3': return 'vec4( ' + code + ', 1.0 )';
  153. case 'v4 = i': return 'vec4( float( ' + code + ' ) )';
  154. case 'i = v1': return 'int( ' + code + ' )';
  155. case 'i = v2': return 'int( ' + code + '.x )';
  156. case 'i = v3': return 'int( ' + code + '.x )';
  157. case 'i = v4': return 'int( ' + code + '.x )';
  158. }
  159. return code;
  160. },
  161. getTypeByFormat: function ( format ) {
  162. return THREE.NodeBuilder.type[ format ] || format;
  163. },
  164. getUuid: function ( uuid, useCache ) {
  165. useCache = useCache !== undefined ? useCache : true;
  166. if ( useCache && this.cache ) uuid = this.cache + '-' + uuid;
  167. return uuid;
  168. },
  169. getElementByIndex: function ( index ) {
  170. return THREE.NodeBuilder.elements[ index ];
  171. },
  172. getIndexByElement: function ( elm ) {
  173. return THREE.NodeBuilder.elements.indexOf( elm );
  174. },
  175. isShader: function ( shader ) {
  176. return this.shader === shader;
  177. },
  178. setShader: function ( shader ) {
  179. this.shader = shader;
  180. return this;
  181. },
  182. getTexelDecodingFunctionFromTexture: function( code, texture ) {
  183. var gammaOverrideLinear = this.getTextureEncodingFromMap( texture, this.requires.gamma && ( this.renderer ? this.renderer.gammaInput : false ) )
  184. return this.getTexelDecodingFunction( code, gammaOverrideLinear );
  185. },
  186. getTexelDecodingFunction: function( value, encoding ) {
  187. var components = this.getEncodingComponents( encoding );
  188. return components[ 0 ] + 'ToLinear' + components[ 1 ].replace( 'value', value );
  189. },
  190. getTexelEncodingFunction: function( value, encoding ) {
  191. var components = this.getEncodingComponents( encoding );
  192. return 'LinearTo' + components[ 0 ] + components[ 1 ].replace( 'value', value );
  193. },
  194. getEncodingComponents: function( encoding ) {
  195. switch ( encoding ) {
  196. case THREE.LinearEncoding:
  197. return [ 'Linear', '( value )' ];
  198. case THREE.sRGBEncoding:
  199. return [ 'sRGB', '( value )' ];
  200. case THREE.RGBEEncoding:
  201. return [ 'RGBE', '( value )' ];
  202. case THREE.RGBM7Encoding:
  203. return [ 'RGBM', '( value, 7.0 )' ];
  204. case THREE.RGBM16Encoding:
  205. return [ 'RGBM', '( value, 16.0 )' ];
  206. case THREE.RGBDEncoding:
  207. return [ 'RGBD', '( value, 256.0 )' ];
  208. case THREE.GammaEncoding:
  209. return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
  210. default:
  211. throw new Error( 'unsupported encoding: ' + encoding );
  212. }
  213. },
  214. getEncodingComponents: function( encoding ) {
  215. switch ( encoding ) {
  216. case THREE.LinearEncoding:
  217. return [ 'Linear', '( value )' ];
  218. case THREE.sRGBEncoding:
  219. return [ 'sRGB', '( value )' ];
  220. case THREE.RGBEEncoding:
  221. return [ 'RGBE', '( value )' ];
  222. case THREE.RGBM7Encoding:
  223. return [ 'RGBM', '( value, 7.0 )' ];
  224. case THREE.RGBM16Encoding:
  225. return [ 'RGBM', '( value, 16.0 )' ];
  226. case THREE.RGBDEncoding:
  227. return [ 'RGBD', '( value, 256.0 )' ];
  228. case THREE.GammaEncoding:
  229. return [ 'Gamma', '( value, float( GAMMA_FACTOR ) )' ];
  230. default:
  231. throw new Error( 'unsupported encoding: ' + encoding );
  232. }
  233. },
  234. getTextureEncodingFromMap: function ( map, gammaOverrideLinear ) {
  235. var encoding;
  236. if ( ! map ) {
  237. encoding = THREE.LinearEncoding;
  238. } else if ( map.isTexture ) {
  239. encoding = map.encoding;
  240. } else if ( map.isWebGLRenderTarget ) {
  241. console.warn( "THREE.WebGLPrograms.getTextureEncodingFromMap: don't use render targets as textures. Use their .texture property instead." );
  242. encoding = map.texture.encoding;
  243. }
  244. // add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
  245. if ( encoding === THREE.LinearEncoding && gammaOverrideLinear ) {
  246. encoding = THREE.GammaEncoding;
  247. }
  248. return encoding;
  249. }
  250. };