WebGLProgram.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107
  1. import { WebGLUniforms } from './WebGLUniforms.js';
  2. import { WebGLShader } from './WebGLShader.js';
  3. import { ShaderChunk } from '../shaders/ShaderChunk.js';
  4. import { NoToneMapping, AddOperation, MixOperation, MultiplyOperation, CubeRefractionMapping, CubeUVReflectionMapping, CubeReflectionMapping, PCFSoftShadowMap, PCFShadowMap, VSMShadowMap, AgXToneMapping, ACESFilmicToneMapping, CineonToneMapping, CustomToneMapping, ReinhardToneMapping, LinearToneMapping, GLSL3, LinearSRGBColorSpace, SRGBColorSpace, LinearDisplayP3ColorSpace, DisplayP3ColorSpace, P3Primaries, Rec709Primaries } from '../../constants.js';
  5. import { ColorManagement } from '../../math/ColorManagement.js';
  6. // From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/
  7. const COMPLETION_STATUS_KHR = 0x91B1;
  8. let programIdCount = 0;
  9. function handleSource( string, errorLine ) {
  10. const lines = string.split( '\n' );
  11. const lines2 = [];
  12. const from = Math.max( errorLine - 6, 0 );
  13. const to = Math.min( errorLine + 6, lines.length );
  14. for ( let i = from; i < to; i ++ ) {
  15. const line = i + 1;
  16. lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` );
  17. }
  18. return lines2.join( '\n' );
  19. }
  20. function getEncodingComponents( colorSpace ) {
  21. const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
  22. const encodingPrimaries = ColorManagement.getPrimaries( colorSpace );
  23. let gamutMapping;
  24. if ( workingPrimaries === encodingPrimaries ) {
  25. gamutMapping = '';
  26. } else if ( workingPrimaries === P3Primaries && encodingPrimaries === Rec709Primaries ) {
  27. gamutMapping = 'LinearDisplayP3ToLinearSRGB';
  28. } else if ( workingPrimaries === Rec709Primaries && encodingPrimaries === P3Primaries ) {
  29. gamutMapping = 'LinearSRGBToLinearDisplayP3';
  30. }
  31. switch ( colorSpace ) {
  32. case LinearSRGBColorSpace:
  33. case LinearDisplayP3ColorSpace:
  34. return [ gamutMapping, 'LinearTransferOETF' ];
  35. case SRGBColorSpace:
  36. case DisplayP3ColorSpace:
  37. return [ gamutMapping, 'sRGBTransferOETF' ];
  38. default:
  39. console.warn( 'THREE.WebGLProgram: Unsupported color space:', colorSpace );
  40. return [ gamutMapping, 'LinearTransferOETF' ];
  41. }
  42. }
  43. function getShaderErrors( gl, shader, type ) {
  44. const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS );
  45. const errors = gl.getShaderInfoLog( shader ).trim();
  46. if ( status && errors === '' ) return '';
  47. const errorMatches = /ERROR: 0:(\d+)/.exec( errors );
  48. if ( errorMatches ) {
  49. // --enable-privileged-webgl-extension
  50. // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
  51. const errorLine = parseInt( errorMatches[ 1 ] );
  52. return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource( gl.getShaderSource( shader ), errorLine );
  53. } else {
  54. return errors;
  55. }
  56. }
  57. function getTexelEncodingFunction( functionName, colorSpace ) {
  58. const components = getEncodingComponents( colorSpace );
  59. return `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}( ${components[ 1 ]}( value ) ); }`;
  60. }
  61. function getToneMappingFunction( functionName, toneMapping ) {
  62. let toneMappingName;
  63. switch ( toneMapping ) {
  64. case LinearToneMapping:
  65. toneMappingName = 'Linear';
  66. break;
  67. case ReinhardToneMapping:
  68. toneMappingName = 'Reinhard';
  69. break;
  70. case CineonToneMapping:
  71. toneMappingName = 'OptimizedCineon';
  72. break;
  73. case ACESFilmicToneMapping:
  74. toneMappingName = 'ACESFilmic';
  75. break;
  76. case AgXToneMapping:
  77. toneMappingName = 'AgX';
  78. break;
  79. case CustomToneMapping:
  80. toneMappingName = 'Custom';
  81. break;
  82. default:
  83. console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping );
  84. toneMappingName = 'Linear';
  85. }
  86. return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';
  87. }
  88. function generateExtensions( parameters ) {
  89. const chunks = [
  90. ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.normalMapTangentSpace || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '',
  91. ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '',
  92. ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '',
  93. ( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : ''
  94. ];
  95. return chunks.filter( filterEmptyLine ).join( '\n' );
  96. }
  97. function generateVertexExtensions( parameters ) {
  98. const chunks = [
  99. parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : ''
  100. ];
  101. return chunks.filter( filterEmptyLine ).join( '\n' );
  102. }
  103. function generateDefines( defines ) {
  104. const chunks = [];
  105. for ( const name in defines ) {
  106. const value = defines[ name ];
  107. if ( value === false ) continue;
  108. chunks.push( '#define ' + name + ' ' + value );
  109. }
  110. return chunks.join( '\n' );
  111. }
  112. function fetchAttributeLocations( gl, program ) {
  113. const attributes = {};
  114. const n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );
  115. for ( let i = 0; i < n; i ++ ) {
  116. const info = gl.getActiveAttrib( program, i );
  117. const name = info.name;
  118. let locationSize = 1;
  119. if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2;
  120. if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3;
  121. if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4;
  122. // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );
  123. attributes[ name ] = {
  124. type: info.type,
  125. location: gl.getAttribLocation( program, name ),
  126. locationSize: locationSize
  127. };
  128. }
  129. return attributes;
  130. }
  131. function filterEmptyLine( string ) {
  132. return string !== '';
  133. }
  134. function replaceLightNums( string, parameters ) {
  135. const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps;
  136. return string
  137. .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
  138. .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
  139. .replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps )
  140. .replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords )
  141. .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
  142. .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
  143. .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
  144. .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
  145. .replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps )
  146. .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
  147. .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );
  148. }
  149. function replaceClippingPlaneNums( string, parameters ) {
  150. return string
  151. .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
  152. .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );
  153. }
  154. // Resolve Includes
  155. const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm;
  156. function resolveIncludes( string ) {
  157. return string.replace( includePattern, includeReplacer );
  158. }
  159. const shaderChunkMap = new Map( [
  160. [ 'encodings_fragment', 'colorspace_fragment' ], // @deprecated, r154
  161. [ 'encodings_pars_fragment', 'colorspace_pars_fragment' ], // @deprecated, r154
  162. [ 'output_fragment', 'opaque_fragment' ], // @deprecated, r154
  163. ] );
  164. function includeReplacer( match, include ) {
  165. let string = ShaderChunk[ include ];
  166. if ( string === undefined ) {
  167. const newInclude = shaderChunkMap.get( include );
  168. if ( newInclude !== undefined ) {
  169. string = ShaderChunk[ newInclude ];
  170. console.warn( 'THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude );
  171. } else {
  172. throw new Error( 'Can not resolve #include <' + include + '>' );
  173. }
  174. }
  175. return resolveIncludes( string );
  176. }
  177. // Unroll Loops
  178. const unrollLoopPattern = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;
  179. function unrollLoops( string ) {
  180. return string.replace( unrollLoopPattern, loopReplacer );
  181. }
  182. function loopReplacer( match, start, end, snippet ) {
  183. let string = '';
  184. for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) {
  185. string += snippet
  186. .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' )
  187. .replace( /UNROLLED_LOOP_INDEX/g, i );
  188. }
  189. return string;
  190. }
  191. //
  192. function generatePrecision( parameters ) {
  193. let precisionstring = `precision ${parameters.precision} float;
  194. precision ${parameters.precision} int;
  195. precision ${parameters.precision} sampler2D;
  196. precision ${parameters.precision} samplerCube;
  197. `;
  198. if ( parameters.isWebGL2 ) {
  199. precisionstring += `precision ${parameters.precision} sampler3D;
  200. precision ${parameters.precision} sampler2DArray;
  201. precision ${parameters.precision} sampler2DShadow;
  202. precision ${parameters.precision} samplerCubeShadow;
  203. precision ${parameters.precision} sampler2DArrayShadow;
  204. precision ${parameters.precision} isampler2D;
  205. precision ${parameters.precision} isampler3D;
  206. precision ${parameters.precision} isamplerCube;
  207. precision ${parameters.precision} isampler2DArray;
  208. precision ${parameters.precision} usampler2D;
  209. precision ${parameters.precision} usampler3D;
  210. precision ${parameters.precision} usamplerCube;
  211. precision ${parameters.precision} usampler2DArray;
  212. `;
  213. }
  214. if ( parameters.precision === 'highp' ) {
  215. precisionstring += '\n#define HIGH_PRECISION';
  216. } else if ( parameters.precision === 'mediump' ) {
  217. precisionstring += '\n#define MEDIUM_PRECISION';
  218. } else if ( parameters.precision === 'lowp' ) {
  219. precisionstring += '\n#define LOW_PRECISION';
  220. }
  221. return precisionstring;
  222. }
  223. function generateShadowMapTypeDefine( parameters ) {
  224. let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';
  225. if ( parameters.shadowMapType === PCFShadowMap ) {
  226. shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
  227. } else if ( parameters.shadowMapType === PCFSoftShadowMap ) {
  228. shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
  229. } else if ( parameters.shadowMapType === VSMShadowMap ) {
  230. shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';
  231. }
  232. return shadowMapTypeDefine;
  233. }
  234. function generateEnvMapTypeDefine( parameters ) {
  235. let envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
  236. if ( parameters.envMap ) {
  237. switch ( parameters.envMapMode ) {
  238. case CubeReflectionMapping:
  239. case CubeRefractionMapping:
  240. envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
  241. break;
  242. case CubeUVReflectionMapping:
  243. envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
  244. break;
  245. }
  246. }
  247. return envMapTypeDefine;
  248. }
  249. function generateEnvMapModeDefine( parameters ) {
  250. let envMapModeDefine = 'ENVMAP_MODE_REFLECTION';
  251. if ( parameters.envMap ) {
  252. switch ( parameters.envMapMode ) {
  253. case CubeRefractionMapping:
  254. envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
  255. break;
  256. }
  257. }
  258. return envMapModeDefine;
  259. }
  260. function generateEnvMapBlendingDefine( parameters ) {
  261. let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';
  262. if ( parameters.envMap ) {
  263. switch ( parameters.combine ) {
  264. case MultiplyOperation:
  265. envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
  266. break;
  267. case MixOperation:
  268. envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
  269. break;
  270. case AddOperation:
  271. envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
  272. break;
  273. }
  274. }
  275. return envMapBlendingDefine;
  276. }
  277. function generateCubeUVSize( parameters ) {
  278. const imageHeight = parameters.envMapCubeUVHeight;
  279. if ( imageHeight === null ) return null;
  280. const maxMip = Math.log2( imageHeight ) - 2;
  281. const texelHeight = 1.0 / imageHeight;
  282. const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) );
  283. return { texelWidth, texelHeight, maxMip };
  284. }
  285. function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
  286. // TODO Send this event to Three.js DevTools
  287. // console.log( 'WebGLProgram', cacheKey );
  288. const gl = renderer.getContext();
  289. const defines = parameters.defines;
  290. let vertexShader = parameters.vertexShader;
  291. let fragmentShader = parameters.fragmentShader;
  292. const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters );
  293. const envMapTypeDefine = generateEnvMapTypeDefine( parameters );
  294. const envMapModeDefine = generateEnvMapModeDefine( parameters );
  295. const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters );
  296. const envMapCubeUVSize = generateCubeUVSize( parameters );
  297. const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters );
  298. const customVertexExtensions = generateVertexExtensions( parameters );
  299. const customDefines = generateDefines( defines );
  300. const program = gl.createProgram();
  301. let prefixVertex, prefixFragment;
  302. let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : '';
  303. if ( parameters.isRawShaderMaterial ) {
  304. prefixVertex = [
  305. '#define SHADER_TYPE ' + parameters.shaderType,
  306. '#define SHADER_NAME ' + parameters.shaderName,
  307. customDefines
  308. ].filter( filterEmptyLine ).join( '\n' );
  309. if ( prefixVertex.length > 0 ) {
  310. prefixVertex += '\n';
  311. }
  312. prefixFragment = [
  313. customExtensions,
  314. '#define SHADER_TYPE ' + parameters.shaderType,
  315. '#define SHADER_NAME ' + parameters.shaderName,
  316. customDefines
  317. ].filter( filterEmptyLine ).join( '\n' );
  318. if ( prefixFragment.length > 0 ) {
  319. prefixFragment += '\n';
  320. }
  321. } else {
  322. prefixVertex = [
  323. generatePrecision( parameters ),
  324. '#define SHADER_TYPE ' + parameters.shaderType,
  325. '#define SHADER_NAME ' + parameters.shaderName,
  326. customDefines,
  327. parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '',
  328. parameters.batching ? '#define USE_BATCHING' : '',
  329. parameters.instancing ? '#define USE_INSTANCING' : '',
  330. parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
  331. parameters.useFog && parameters.fog ? '#define USE_FOG' : '',
  332. parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '',
  333. parameters.map ? '#define USE_MAP' : '',
  334. parameters.envMap ? '#define USE_ENVMAP' : '',
  335. parameters.envMap ? '#define ' + envMapModeDefine : '',
  336. parameters.lightMap ? '#define USE_LIGHTMAP' : '',
  337. parameters.aoMap ? '#define USE_AOMAP' : '',
  338. parameters.bumpMap ? '#define USE_BUMPMAP' : '',
  339. parameters.normalMap ? '#define USE_NORMALMAP' : '',
  340. parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',
  341. parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',
  342. parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '',
  343. parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
  344. parameters.anisotropy ? '#define USE_ANISOTROPY' : '',
  345. parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '',
  346. parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
  347. parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
  348. parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
  349. parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',
  350. parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',
  351. parameters.specularMap ? '#define USE_SPECULARMAP' : '',
  352. parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '',
  353. parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '',
  354. parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
  355. parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
  356. parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
  357. parameters.alphaHash ? '#define USE_ALPHAHASH' : '',
  358. parameters.transmission ? '#define USE_TRANSMISSION' : '',
  359. parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
  360. parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
  361. parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',
  362. parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',
  363. //
  364. parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '',
  365. parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '',
  366. parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '',
  367. parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '',
  368. parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '',
  369. parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '',
  370. parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '',
  371. parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '',
  372. parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '',
  373. parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '',
  374. parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '',
  375. parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '',
  376. parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '',
  377. parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '',
  378. parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '',
  379. parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '',
  380. parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '',
  381. parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '',
  382. parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '',
  383. parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '',
  384. parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '',
  385. parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '',
  386. parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '',
  387. //
  388. parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',
  389. parameters.vertexColors ? '#define USE_COLOR' : '',
  390. parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
  391. parameters.vertexUv1s ? '#define USE_UV1' : '',
  392. parameters.vertexUv2s ? '#define USE_UV2' : '',
  393. parameters.vertexUv3s ? '#define USE_UV3' : '',
  394. parameters.pointsUvs ? '#define USE_POINTS_UV' : '',
  395. parameters.flatShading ? '#define FLAT_SHADED' : '',
  396. parameters.skinning ? '#define USE_SKINNING' : '',
  397. parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
  398. parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
  399. ( parameters.morphColors && parameters.isWebGL2 ) ? '#define USE_MORPHCOLORS' : '',
  400. ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE' : '',
  401. ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '',
  402. ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '',
  403. parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
  404. parameters.flipSided ? '#define FLIP_SIDED' : '',
  405. parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
  406. parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
  407. parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
  408. parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
  409. parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '',
  410. parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
  411. ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
  412. 'uniform mat4 modelMatrix;',
  413. 'uniform mat4 modelViewMatrix;',
  414. 'uniform mat4 projectionMatrix;',
  415. 'uniform mat4 viewMatrix;',
  416. 'uniform mat3 normalMatrix;',
  417. 'uniform vec3 cameraPosition;',
  418. 'uniform bool isOrthographic;',
  419. '#ifdef USE_INSTANCING',
  420. ' attribute mat4 instanceMatrix;',
  421. '#endif',
  422. '#ifdef USE_INSTANCING_COLOR',
  423. ' attribute vec3 instanceColor;',
  424. '#endif',
  425. 'attribute vec3 position;',
  426. 'attribute vec3 normal;',
  427. 'attribute vec2 uv;',
  428. '#ifdef USE_UV1',
  429. ' attribute vec2 uv1;',
  430. '#endif',
  431. '#ifdef USE_UV2',
  432. ' attribute vec2 uv2;',
  433. '#endif',
  434. '#ifdef USE_UV3',
  435. ' attribute vec2 uv3;',
  436. '#endif',
  437. '#ifdef USE_TANGENT',
  438. ' attribute vec4 tangent;',
  439. '#endif',
  440. '#if defined( USE_COLOR_ALPHA )',
  441. ' attribute vec4 color;',
  442. '#elif defined( USE_COLOR )',
  443. ' attribute vec3 color;',
  444. '#endif',
  445. '#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )',
  446. ' attribute vec3 morphTarget0;',
  447. ' attribute vec3 morphTarget1;',
  448. ' attribute vec3 morphTarget2;',
  449. ' attribute vec3 morphTarget3;',
  450. ' #ifdef USE_MORPHNORMALS',
  451. ' attribute vec3 morphNormal0;',
  452. ' attribute vec3 morphNormal1;',
  453. ' attribute vec3 morphNormal2;',
  454. ' attribute vec3 morphNormal3;',
  455. ' #else',
  456. ' attribute vec3 morphTarget4;',
  457. ' attribute vec3 morphTarget5;',
  458. ' attribute vec3 morphTarget6;',
  459. ' attribute vec3 morphTarget7;',
  460. ' #endif',
  461. '#endif',
  462. '#ifdef USE_SKINNING',
  463. ' attribute vec4 skinIndex;',
  464. ' attribute vec4 skinWeight;',
  465. '#endif',
  466. '\n'
  467. ].filter( filterEmptyLine ).join( '\n' );
  468. prefixFragment = [
  469. customExtensions,
  470. generatePrecision( parameters ),
  471. '#define SHADER_TYPE ' + parameters.shaderType,
  472. '#define SHADER_NAME ' + parameters.shaderName,
  473. customDefines,
  474. parameters.useFog && parameters.fog ? '#define USE_FOG' : '',
  475. parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '',
  476. parameters.map ? '#define USE_MAP' : '',
  477. parameters.matcap ? '#define USE_MATCAP' : '',
  478. parameters.envMap ? '#define USE_ENVMAP' : '',
  479. parameters.envMap ? '#define ' + envMapTypeDefine : '',
  480. parameters.envMap ? '#define ' + envMapModeDefine : '',
  481. parameters.envMap ? '#define ' + envMapBlendingDefine : '',
  482. envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '',
  483. envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '',
  484. envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '',
  485. parameters.lightMap ? '#define USE_LIGHTMAP' : '',
  486. parameters.aoMap ? '#define USE_AOMAP' : '',
  487. parameters.bumpMap ? '#define USE_BUMPMAP' : '',
  488. parameters.normalMap ? '#define USE_NORMALMAP' : '',
  489. parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',
  490. parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',
  491. parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
  492. parameters.anisotropy ? '#define USE_ANISOTROPY' : '',
  493. parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '',
  494. parameters.clearcoat ? '#define USE_CLEARCOAT' : '',
  495. parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',
  496. parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
  497. parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
  498. parameters.iridescence ? '#define USE_IRIDESCENCE' : '',
  499. parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',
  500. parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',
  501. parameters.specularMap ? '#define USE_SPECULARMAP' : '',
  502. parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '',
  503. parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '',
  504. parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
  505. parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
  506. parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
  507. parameters.alphaTest ? '#define USE_ALPHATEST' : '',
  508. parameters.alphaHash ? '#define USE_ALPHAHASH' : '',
  509. parameters.sheen ? '#define USE_SHEEN' : '',
  510. parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',
  511. parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',
  512. parameters.transmission ? '#define USE_TRANSMISSION' : '',
  513. parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
  514. parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
  515. parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',
  516. parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '',
  517. parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
  518. parameters.vertexUv1s ? '#define USE_UV1' : '',
  519. parameters.vertexUv2s ? '#define USE_UV2' : '',
  520. parameters.vertexUv3s ? '#define USE_UV3' : '',
  521. parameters.pointsUvs ? '#define USE_POINTS_UV' : '',
  522. parameters.gradientMap ? '#define USE_GRADIENTMAP' : '',
  523. parameters.flatShading ? '#define FLAT_SHADED' : '',
  524. parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
  525. parameters.flipSided ? '#define FLIP_SIDED' : '',
  526. parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
  527. parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
  528. parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
  529. parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
  530. parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '',
  531. parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
  532. parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
  533. ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
  534. 'uniform mat4 viewMatrix;',
  535. 'uniform vec3 cameraPosition;',
  536. 'uniform bool isOrthographic;',
  537. ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
  538. ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
  539. ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',
  540. parameters.dithering ? '#define DITHERING' : '',
  541. parameters.opaque ? '#define OPAQUE' : '',
  542. ShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below
  543. getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ),
  544. parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',
  545. '\n'
  546. ].filter( filterEmptyLine ).join( '\n' );
  547. }
  548. vertexShader = resolveIncludes( vertexShader );
  549. vertexShader = replaceLightNums( vertexShader, parameters );
  550. vertexShader = replaceClippingPlaneNums( vertexShader, parameters );
  551. fragmentShader = resolveIncludes( fragmentShader );
  552. fragmentShader = replaceLightNums( fragmentShader, parameters );
  553. fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );
  554. vertexShader = unrollLoops( vertexShader );
  555. fragmentShader = unrollLoops( fragmentShader );
  556. if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) {
  557. // GLSL 3.0 conversion for built-in materials and ShaderMaterial
  558. versionString = '#version 300 es\n';
  559. prefixVertex = [
  560. customVertexExtensions,
  561. 'precision mediump sampler2DArray;',
  562. '#define attribute in',
  563. '#define varying out',
  564. '#define texture2D texture'
  565. ].join( '\n' ) + '\n' + prefixVertex;
  566. prefixFragment = [
  567. 'precision mediump sampler2DArray;',
  568. '#define varying in',
  569. ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;',
  570. ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',
  571. '#define gl_FragDepthEXT gl_FragDepth',
  572. '#define texture2D texture',
  573. '#define textureCube texture',
  574. '#define texture2DProj textureProj',
  575. '#define texture2DLodEXT textureLod',
  576. '#define texture2DProjLodEXT textureProjLod',
  577. '#define textureCubeLodEXT textureLod',
  578. '#define texture2DGradEXT textureGrad',
  579. '#define texture2DProjGradEXT textureProjGrad',
  580. '#define textureCubeGradEXT textureGrad'
  581. ].join( '\n' ) + '\n' + prefixFragment;
  582. }
  583. const vertexGlsl = versionString + prefixVertex + vertexShader;
  584. const fragmentGlsl = versionString + prefixFragment + fragmentShader;
  585. // console.log( '*VERTEX*', vertexGlsl );
  586. // console.log( '*FRAGMENT*', fragmentGlsl );
  587. const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
  588. const glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
  589. gl.attachShader( program, glVertexShader );
  590. gl.attachShader( program, glFragmentShader );
  591. // Force a particular attribute to index 0.
  592. if ( parameters.index0AttributeName !== undefined ) {
  593. gl.bindAttribLocation( program, 0, parameters.index0AttributeName );
  594. } else if ( parameters.morphTargets === true ) {
  595. // programs with morphTargets displace position out of attribute 0
  596. gl.bindAttribLocation( program, 0, 'position' );
  597. }
  598. gl.linkProgram( program );
  599. function onFirstUse( self ) {
  600. // check for link errors
  601. if ( renderer.debug.checkShaderErrors ) {
  602. const programLog = gl.getProgramInfoLog( program ).trim();
  603. const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();
  604. const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();
  605. let runnable = true;
  606. let haveDiagnostics = true;
  607. if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {
  608. runnable = false;
  609. if ( typeof renderer.debug.onShaderError === 'function' ) {
  610. renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader );
  611. } else {
  612. // default error reporting
  613. const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );
  614. const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );
  615. console.error(
  616. 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' +
  617. 'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' +
  618. 'Material Name: ' + self.name + '\n' +
  619. 'Material Type: ' + self.type + '\n\n' +
  620. 'Program Info Log: ' + programLog + '\n' +
  621. vertexErrors + '\n' +
  622. fragmentErrors
  623. );
  624. }
  625. } else if ( programLog !== '' ) {
  626. console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog );
  627. } else if ( vertexLog === '' || fragmentLog === '' ) {
  628. haveDiagnostics = false;
  629. }
  630. if ( haveDiagnostics ) {
  631. self.diagnostics = {
  632. runnable: runnable,
  633. programLog: programLog,
  634. vertexShader: {
  635. log: vertexLog,
  636. prefix: prefixVertex
  637. },
  638. fragmentShader: {
  639. log: fragmentLog,
  640. prefix: prefixFragment
  641. }
  642. };
  643. }
  644. }
  645. // Clean up
  646. // Crashes in iOS9 and iOS10. #18402
  647. // gl.detachShader( program, glVertexShader );
  648. // gl.detachShader( program, glFragmentShader );
  649. gl.deleteShader( glVertexShader );
  650. gl.deleteShader( glFragmentShader );
  651. cachedUniforms = new WebGLUniforms( gl, program );
  652. cachedAttributes = fetchAttributeLocations( gl, program );
  653. }
  654. // set up caching for uniform locations
  655. let cachedUniforms;
  656. this.getUniforms = function () {
  657. if ( cachedUniforms === undefined ) {
  658. // Populates cachedUniforms and cachedAttributes
  659. onFirstUse( this );
  660. }
  661. return cachedUniforms;
  662. };
  663. // set up caching for attribute locations
  664. let cachedAttributes;
  665. this.getAttributes = function () {
  666. if ( cachedAttributes === undefined ) {
  667. // Populates cachedAttributes and cachedUniforms
  668. onFirstUse( this );
  669. }
  670. return cachedAttributes;
  671. };
  672. // indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported,
  673. // flag the program as ready immediately. It may cause a stall when it's first used.
  674. let programReady = ( parameters.rendererExtensionParallelShaderCompile === false );
  675. this.isReady = function () {
  676. if ( programReady === false ) {
  677. programReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR );
  678. }
  679. return programReady;
  680. };
  681. // free resource
  682. this.destroy = function () {
  683. bindingStates.releaseStatesOfProgram( this );
  684. gl.deleteProgram( program );
  685. this.program = undefined;
  686. };
  687. //
  688. this.type = parameters.shaderType;
  689. this.name = parameters.shaderName;
  690. this.id = programIdCount ++;
  691. this.cacheKey = cacheKey;
  692. this.usedTimes = 1;
  693. this.program = program;
  694. this.vertexShader = glVertexShader;
  695. this.fragmentShader = glFragmentShader;
  696. return this;
  697. }
  698. export { WebGLProgram };
粤ICP备19079148号