ShaderBuilder.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. THREE.WebGLRenderer.ShaderBuilder = function ( renderer, info ) {
  2. this.renderer = renderer;
  3. this.info = info;
  4. this.programs = [],
  5. this.programs_counter = 0;
  6. };
  7. THREE.extend( THREE.WebGLRenderer.ShaderBuilder.prototype, {
  8. buildProgram: function ( shaderID, fragmentShader, vertexShader, uniforms, attributes, defines, parameters ) {
  9. var renderer = this.renderer;
  10. var p, pl, d, program, code;
  11. var chunks = [];
  12. // Generate code
  13. if ( shaderID ) {
  14. chunks.push( shaderID );
  15. } else {
  16. chunks.push( fragmentShader );
  17. chunks.push( vertexShader );
  18. }
  19. for ( d in defines ) {
  20. chunks.push( d );
  21. chunks.push( defines[ d ] );
  22. }
  23. for ( p in parameters ) {
  24. chunks.push( p );
  25. chunks.push( parameters[ p ] );
  26. }
  27. code = chunks.join();
  28. // Check if code has been already compiled
  29. for ( p = 0, pl = this.programs.length; p < pl; p ++ ) {
  30. var programInfo = this.programs[ p ];
  31. if ( programInfo.code === code ) {
  32. //console.log( "Code already compiled." /*: \n\n" + code*/ );
  33. programInfo.usedTimes ++;
  34. return programInfo.program;
  35. }
  36. }
  37. var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC";
  38. if ( parameters.shadowMapType === THREE.PCFShadowMap ) {
  39. shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF";
  40. } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) {
  41. shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT";
  42. }
  43. //console.log( "building new program " );
  44. //
  45. var customDefines = this.generateDefines( defines );
  46. //
  47. var prefix_vertex = [
  48. "precision " + renderer.precision + " float;",
  49. customDefines,
  50. renderer.supportsVertexTextures ? "#define VERTEX_TEXTURES" : "",
  51. parameters.gammaInput ? "#define GAMMA_INPUT" : "",
  52. parameters.gammaOutput ? "#define GAMMA_OUTPUT" : "",
  53. parameters.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "",
  54. "#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
  55. "#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
  56. "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
  57. "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
  58. "#define MAX_SHADOWS " + parameters.maxShadows,
  59. "#define MAX_BONES " + parameters.maxBones,
  60. parameters.map ? "#define USE_MAP" : "",
  61. parameters.envMap ? "#define USE_ENVMAP" : "",
  62. parameters.lightMap ? "#define USE_LIGHTMAP" : "",
  63. parameters.bumpMap ? "#define USE_BUMPMAP" : "",
  64. parameters.normalMap ? "#define USE_NORMALMAP" : "",
  65. parameters.specularMap ? "#define USE_SPECULARMAP" : "",
  66. parameters.vertexColors ? "#define USE_COLOR" : "",
  67. parameters.skinning ? "#define USE_SKINNING" : "",
  68. parameters.useVertexTexture ? "#define BONE_TEXTURE" : "",
  69. parameters.boneTextureWidth ? "#define N_BONE_PIXEL_X " + parameters.boneTextureWidth.toFixed( 1 ) : "",
  70. parameters.boneTextureHeight ? "#define N_BONE_PIXEL_Y " + parameters.boneTextureHeight.toFixed( 1 ) : "",
  71. parameters.morphTargets ? "#define USE_MORPHTARGETS" : "",
  72. parameters.morphNormals ? "#define USE_MORPHNORMALS" : "",
  73. parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
  74. parameters.wrapAround ? "#define WRAP_AROUND" : "",
  75. parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
  76. parameters.flipSided ? "#define FLIP_SIDED" : "",
  77. parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
  78. parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
  79. parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
  80. parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
  81. parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "",
  82. "uniform mat4 modelMatrix;",
  83. "uniform mat4 modelViewMatrix;",
  84. "uniform mat4 projectionMatrix;",
  85. "uniform mat4 viewMatrix;",
  86. "uniform mat3 normalMatrix;",
  87. "uniform vec3 cameraPosition;",
  88. "attribute vec3 position;",
  89. "attribute vec3 normal;",
  90. "attribute vec2 uv;",
  91. "attribute vec2 uv2;",
  92. "#ifdef USE_COLOR",
  93. "attribute vec3 color;",
  94. "#endif",
  95. "#ifdef USE_MORPHTARGETS",
  96. "attribute vec3 morphTarget0;",
  97. "attribute vec3 morphTarget1;",
  98. "attribute vec3 morphTarget2;",
  99. "attribute vec3 morphTarget3;",
  100. "#ifdef USE_MORPHNORMALS",
  101. "attribute vec3 morphNormal0;",
  102. "attribute vec3 morphNormal1;",
  103. "attribute vec3 morphNormal2;",
  104. "attribute vec3 morphNormal3;",
  105. "#else",
  106. "attribute vec3 morphTarget4;",
  107. "attribute vec3 morphTarget5;",
  108. "attribute vec3 morphTarget6;",
  109. "attribute vec3 morphTarget7;",
  110. "#endif",
  111. "#endif",
  112. "#ifdef USE_SKINNING",
  113. "attribute vec4 skinIndex;",
  114. "attribute vec4 skinWeight;",
  115. "#endif",
  116. ""
  117. ].join("\n");
  118. var prefix_fragment = [
  119. "precision " + renderer.precision + " float;",
  120. ( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "",
  121. customDefines,
  122. "#define MAX_DIR_LIGHTS " + parameters.maxDirLights,
  123. "#define MAX_POINT_LIGHTS " + parameters.maxPointLights,
  124. "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights,
  125. "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights,
  126. "#define MAX_SHADOWS " + parameters.maxShadows,
  127. parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "",
  128. parameters.gammaInput ? "#define GAMMA_INPUT" : "",
  129. parameters.gammaOutput ? "#define GAMMA_OUTPUT" : "",
  130. parameters.physicallyBasedShading ? "#define PHYSICALLY_BASED_SHADING" : "",
  131. ( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "",
  132. ( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "",
  133. parameters.map ? "#define USE_MAP" : "",
  134. parameters.envMap ? "#define USE_ENVMAP" : "",
  135. parameters.lightMap ? "#define USE_LIGHTMAP" : "",
  136. parameters.bumpMap ? "#define USE_BUMPMAP" : "",
  137. parameters.normalMap ? "#define USE_NORMALMAP" : "",
  138. parameters.specularMap ? "#define USE_SPECULARMAP" : "",
  139. parameters.vertexColors ? "#define USE_COLOR" : "",
  140. parameters.metal ? "#define METAL" : "",
  141. parameters.perPixel ? "#define PHONG_PER_PIXEL" : "",
  142. parameters.wrapAround ? "#define WRAP_AROUND" : "",
  143. parameters.doubleSided ? "#define DOUBLE_SIDED" : "",
  144. parameters.flipSided ? "#define FLIP_SIDED" : "",
  145. parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "",
  146. parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "",
  147. parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "",
  148. parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "",
  149. "uniform mat4 viewMatrix;",
  150. "uniform vec3 cameraPosition;",
  151. ""
  152. ].join("\n");
  153. program = renderer.compileShader(prefix_vertex + vertexShader, prefix_fragment + fragmentShader);
  154. //console.log( prefix_fragment + fragmentShader );
  155. //console.log( prefix_vertex + vertexShader );
  156. program.uniforms = {};
  157. program.attributes = {};
  158. var identifiers, u, a, i;
  159. // cache uniform locations
  160. identifiers = [
  161. 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition',
  162. 'morphTargetInfluences'
  163. ];
  164. if ( parameters.useVertexTexture ) {
  165. identifiers.push( 'boneTexture' );
  166. } else {
  167. identifiers.push( 'boneGlobalMatrices' );
  168. }
  169. for ( u in uniforms ) {
  170. identifiers.push( u );
  171. }
  172. this.cacheUniformLocations( program, identifiers );
  173. // cache attributes locations
  174. identifiers = [
  175. "position", "normal", "uv", "uv2", "tangent", "color",
  176. "skinIndex", "skinWeight", "lineDistance"
  177. ];
  178. for ( i = 0; i < parameters.maxMorphTargets; i ++ ) {
  179. identifiers.push( "morphTarget" + i );
  180. }
  181. for ( i = 0; i < parameters.maxMorphNormals; i ++ ) {
  182. identifiers.push( "morphNormal" + i );
  183. }
  184. for ( a in attributes ) {
  185. identifiers.push( a );
  186. }
  187. this.cacheAttributeLocations( program, identifiers );
  188. program.id = this.programs_counter ++;
  189. this.programs.push( { program: program, code: code, usedTimes: 1 } );
  190. this.info.memory.programs = this.programs.length;
  191. return program;
  192. },
  193. generateDefines: function ( defines ) {
  194. var value, chunk, chunks = [];
  195. for ( var d in defines ) {
  196. value = defines[ d ];
  197. if ( value === false ) continue;
  198. chunk = "#define " + d + " " + value;
  199. chunks.push( chunk );
  200. }
  201. return chunks.join( "\n" );
  202. },
  203. // Shader parameters cache
  204. cacheUniformLocations: function ( program, identifiers ) {
  205. var i, l, id, renderer = this.renderer;
  206. for ( i = 0, l = identifiers.length; i < l; i ++ ) {
  207. id = identifiers[ i ];
  208. program.uniforms[ id ] = renderer.getUniformLocation( program, id );
  209. }
  210. },
  211. cacheAttributeLocations: function ( program, identifiers ) {
  212. var i, l, id, renderer = this.renderer;
  213. for( i = 0, l = identifiers.length; i < l; i ++ ) {
  214. id = identifiers[ i ];
  215. program.attributes[ id ] = renderer.getAttribLocation( program, id );
  216. }
  217. },
  218. removeProgram: function ( program ) {
  219. var i, il, programInfo;
  220. var deleteProgram = false;
  221. var programs = this.programs;
  222. for ( i = 0, il = programs.length; i < il; i ++ ) {
  223. programInfo = programs[ i ];
  224. if ( programInfo.program === program ) {
  225. programInfo.usedTimes --;
  226. if ( programInfo.usedTimes === 0 ) {
  227. deleteProgram = true;
  228. }
  229. break;
  230. }
  231. }
  232. if ( deleteProgram === true ) {
  233. // avoid using array.splice, this is costlier than creating new array from scratch
  234. var newPrograms = [];
  235. for ( i = 0, il = programs.length; i < il; i ++ ) {
  236. programInfo = programs[ i ];
  237. if ( programInfo.program !== program ) {
  238. newPrograms.push( programInfo );
  239. }
  240. }
  241. this.programs = newPrograms;
  242. this.renderer.deleteProgram( program );
  243. this.info.memory.programs --;
  244. }
  245. }
  246. } );