WebGLTextures.js 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884
  1. import { LinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, RGBAFormat, DepthFormat, DepthStencilFormat, UnsignedShortType, UnsignedIntType, UnsignedInt248Type, FloatType, HalfFloatType, MirroredRepeatWrapping, ClampToEdgeWrapping, RepeatWrapping, sRGBEncoding, LinearEncoding, UnsignedByteType, _SRGBAFormat } from '../../constants.js';
  2. import * as MathUtils from '../../math/MathUtils.js';
  3. import { ImageUtils } from '../../extras/ImageUtils.js';
  4. import { createElementNS } from '../../utils.js';
  5. function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {
  6. const isWebGL2 = capabilities.isWebGL2;
  7. const maxTextures = capabilities.maxTextures;
  8. const maxCubemapSize = capabilities.maxCubemapSize;
  9. const maxTextureSize = capabilities.maxTextureSize;
  10. const maxSamples = capabilities.maxSamples;
  11. const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null;
  12. const _videoTextures = new WeakMap();
  13. let _canvas;
  14. const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source
  15. // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas,
  16. // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")!
  17. // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d).
  18. let useOffscreenCanvas = false;
  19. try {
  20. useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'
  21. && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null;
  22. } catch ( err ) {
  23. // Ignore any errors
  24. }
  25. function createCanvas( width, height ) {
  26. // Use OffscreenCanvas when available. Specially needed in web workers
  27. return useOffscreenCanvas ?
  28. new OffscreenCanvas( width, height ) : createElementNS( 'canvas' );
  29. }
  30. function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) {
  31. let scale = 1;
  32. // handle case if texture exceeds max size
  33. if ( image.width > maxSize || image.height > maxSize ) {
  34. scale = maxSize / Math.max( image.width, image.height );
  35. }
  36. // only perform resize if necessary
  37. if ( scale < 1 || needsPowerOfTwo === true ) {
  38. // only perform resize for certain image types
  39. if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
  40. ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
  41. ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
  42. const floor = needsPowerOfTwo ? MathUtils.floorPowerOfTwo : Math.floor;
  43. const width = floor( scale * image.width );
  44. const height = floor( scale * image.height );
  45. if ( _canvas === undefined ) _canvas = createCanvas( width, height );
  46. // cube textures can't reuse the same canvas
  47. const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;
  48. canvas.width = width;
  49. canvas.height = height;
  50. const context = canvas.getContext( '2d' );
  51. context.drawImage( image, 0, 0, width, height );
  52. console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' );
  53. return canvas;
  54. } else {
  55. if ( 'data' in image ) {
  56. console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' );
  57. }
  58. return image;
  59. }
  60. }
  61. return image;
  62. }
  63. function isPowerOfTwo( image ) {
  64. return MathUtils.isPowerOfTwo( image.width ) && MathUtils.isPowerOfTwo( image.height );
  65. }
  66. function textureNeedsPowerOfTwo( texture ) {
  67. if ( isWebGL2 ) return false;
  68. return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) ||
  69. ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter );
  70. }
  71. function textureNeedsGenerateMipmaps( texture, supportsMips ) {
  72. return texture.generateMipmaps && supportsMips &&
  73. texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;
  74. }
  75. function generateMipmap( target ) {
  76. _gl.generateMipmap( target );
  77. }
  78. function getInternalFormat( internalFormatName, glFormat, glType, encoding, isVideoTexture = false ) {
  79. if ( isWebGL2 === false ) return glFormat;
  80. if ( internalFormatName !== null ) {
  81. if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];
  82. console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' );
  83. }
  84. let internalFormat = glFormat;
  85. if ( glFormat === _gl.RED ) {
  86. if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F;
  87. if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F;
  88. if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8;
  89. }
  90. if ( glFormat === _gl.RG ) {
  91. if ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F;
  92. if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F;
  93. if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8;
  94. }
  95. if ( glFormat === _gl.RGBA ) {
  96. if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F;
  97. if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F;
  98. if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( encoding === sRGBEncoding && isVideoTexture === false ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8;
  99. if ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4;
  100. if ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1;
  101. }
  102. if ( internalFormat === _gl.R16F || internalFormat === _gl.R32F ||
  103. internalFormat === _gl.RG16F || internalFormat === _gl.RG32F ||
  104. internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) {
  105. extensions.get( 'EXT_color_buffer_float' );
  106. }
  107. return internalFormat;
  108. }
  109. function getMipLevels( texture, image, supportsMips ) {
  110. if ( textureNeedsGenerateMipmaps( texture, supportsMips ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) {
  111. return Math.log2( Math.max( image.width, image.height ) ) + 1;
  112. } else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) {
  113. // user-defined mipmaps
  114. return texture.mipmaps.length;
  115. } else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) {
  116. return image.mipmaps.length;
  117. } else {
  118. // texture without mipmaps (only base level)
  119. return 1;
  120. }
  121. }
  122. // Fallback filters for non-power-of-2 textures
  123. function filterFallback( f ) {
  124. if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) {
  125. return _gl.NEAREST;
  126. }
  127. return _gl.LINEAR;
  128. }
  129. //
  130. function onTextureDispose( event ) {
  131. const texture = event.target;
  132. texture.removeEventListener( 'dispose', onTextureDispose );
  133. deallocateTexture( texture );
  134. if ( texture.isVideoTexture ) {
  135. _videoTextures.delete( texture );
  136. }
  137. }
  138. function onRenderTargetDispose( event ) {
  139. const renderTarget = event.target;
  140. renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );
  141. deallocateRenderTarget( renderTarget );
  142. }
  143. //
  144. function deallocateTexture( texture ) {
  145. const textureProperties = properties.get( texture );
  146. if ( textureProperties.__webglInit === undefined ) return;
  147. // check if it's necessary to remove the WebGLTexture object
  148. const source = texture.source;
  149. const webglTextures = _sources.get( source );
  150. if ( webglTextures ) {
  151. const webglTexture = webglTextures[ textureProperties.__cacheKey ];
  152. webglTexture.usedTimes --;
  153. // the WebGLTexture object is not used anymore, remove it
  154. if ( webglTexture.usedTimes === 0 ) {
  155. deleteTexture( texture );
  156. }
  157. // remove the weak map entry if no WebGLTexture uses the source anymore
  158. if ( Object.keys( webglTextures ).length === 0 ) {
  159. _sources.delete( source );
  160. }
  161. }
  162. properties.remove( texture );
  163. }
  164. function deleteTexture( texture ) {
  165. const textureProperties = properties.get( texture );
  166. _gl.deleteTexture( textureProperties.__webglTexture );
  167. const source = texture.source;
  168. const webglTextures = _sources.get( source );
  169. delete webglTextures[ textureProperties.__cacheKey ];
  170. info.memory.textures --;
  171. }
  172. function deallocateRenderTarget( renderTarget ) {
  173. const texture = renderTarget.texture;
  174. const renderTargetProperties = properties.get( renderTarget );
  175. const textureProperties = properties.get( texture );
  176. if ( textureProperties.__webglTexture !== undefined ) {
  177. _gl.deleteTexture( textureProperties.__webglTexture );
  178. info.memory.textures --;
  179. }
  180. if ( renderTarget.depthTexture ) {
  181. renderTarget.depthTexture.dispose();
  182. }
  183. if ( renderTarget.isWebGLCubeRenderTarget ) {
  184. for ( let i = 0; i < 6; i ++ ) {
  185. _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
  186. if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
  187. }
  188. } else {
  189. _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
  190. if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
  191. if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer );
  192. if ( renderTargetProperties.__webglColorRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer );
  193. if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );
  194. }
  195. if ( renderTarget.isWebGLMultipleRenderTargets ) {
  196. for ( let i = 0, il = texture.length; i < il; i ++ ) {
  197. const attachmentProperties = properties.get( texture[ i ] );
  198. if ( attachmentProperties.__webglTexture ) {
  199. _gl.deleteTexture( attachmentProperties.__webglTexture );
  200. info.memory.textures --;
  201. }
  202. properties.remove( texture[ i ] );
  203. }
  204. }
  205. properties.remove( texture );
  206. properties.remove( renderTarget );
  207. }
  208. //
  209. let textureUnits = 0;
  210. function resetTextureUnits() {
  211. textureUnits = 0;
  212. }
  213. function allocateTextureUnit() {
  214. const textureUnit = textureUnits;
  215. if ( textureUnit >= maxTextures ) {
  216. console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures );
  217. }
  218. textureUnits += 1;
  219. return textureUnit;
  220. }
  221. function getTextureCacheKey( texture ) {
  222. const array = [];
  223. array.push( texture.wrapS );
  224. array.push( texture.wrapT );
  225. array.push( texture.magFilter );
  226. array.push( texture.minFilter );
  227. array.push( texture.anisotropy );
  228. array.push( texture.internalFormat );
  229. array.push( texture.format );
  230. array.push( texture.type );
  231. array.push( texture.generateMipmaps );
  232. array.push( texture.premultiplyAlpha );
  233. array.push( texture.flipY );
  234. array.push( texture.unpackAlignment );
  235. array.push( texture.encoding );
  236. return array.join();
  237. }
  238. //
  239. function setTexture2D( texture, slot ) {
  240. const textureProperties = properties.get( texture );
  241. if ( texture.isVideoTexture ) updateVideoTexture( texture );
  242. if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
  243. const image = texture.image;
  244. if ( image === null ) {
  245. console.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' );
  246. } else if ( image.complete === false ) {
  247. console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );
  248. } else {
  249. uploadTexture( textureProperties, texture, slot );
  250. return;
  251. }
  252. }
  253. state.activeTexture( _gl.TEXTURE0 + slot );
  254. state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture );
  255. }
  256. function setTexture2DArray( texture, slot ) {
  257. const textureProperties = properties.get( texture );
  258. if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
  259. uploadTexture( textureProperties, texture, slot );
  260. return;
  261. }
  262. state.activeTexture( _gl.TEXTURE0 + slot );
  263. state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture );
  264. }
  265. function setTexture3D( texture, slot ) {
  266. const textureProperties = properties.get( texture );
  267. if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
  268. uploadTexture( textureProperties, texture, slot );
  269. return;
  270. }
  271. state.activeTexture( _gl.TEXTURE0 + slot );
  272. state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture );
  273. }
  274. function setTextureCube( texture, slot ) {
  275. const textureProperties = properties.get( texture );
  276. if ( texture.version > 0 && textureProperties.__version !== texture.version ) {
  277. uploadCubeTexture( textureProperties, texture, slot );
  278. return;
  279. }
  280. state.activeTexture( _gl.TEXTURE0 + slot );
  281. state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
  282. }
  283. const wrappingToGL = {
  284. [ RepeatWrapping ]: _gl.REPEAT,
  285. [ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE,
  286. [ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT
  287. };
  288. const filterToGL = {
  289. [ NearestFilter ]: _gl.NEAREST,
  290. [ NearestMipmapNearestFilter ]: _gl.NEAREST_MIPMAP_NEAREST,
  291. [ NearestMipmapLinearFilter ]: _gl.NEAREST_MIPMAP_LINEAR,
  292. [ LinearFilter ]: _gl.LINEAR,
  293. [ LinearMipmapNearestFilter ]: _gl.LINEAR_MIPMAP_NEAREST,
  294. [ LinearMipmapLinearFilter ]: _gl.LINEAR_MIPMAP_LINEAR
  295. };
  296. function setTextureParameters( textureType, texture, supportsMips ) {
  297. if ( supportsMips ) {
  298. _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] );
  299. _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] );
  300. if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) {
  301. _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] );
  302. }
  303. _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] );
  304. _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] );
  305. } else {
  306. _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
  307. _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
  308. if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) {
  309. _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, _gl.CLAMP_TO_EDGE );
  310. }
  311. if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) {
  312. console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' );
  313. }
  314. _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
  315. _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
  316. if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) {
  317. console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' );
  318. }
  319. }
  320. if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {
  321. const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
  322. if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2
  323. if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only
  324. if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {
  325. _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
  326. properties.get( texture ).__currentAnisotropy = texture.anisotropy;
  327. }
  328. }
  329. }
  330. function initTexture( textureProperties, texture ) {
  331. let forceUpload = false;
  332. if ( textureProperties.__webglInit === undefined ) {
  333. textureProperties.__webglInit = true;
  334. texture.addEventListener( 'dispose', onTextureDispose );
  335. }
  336. // create Source <-> WebGLTextures mapping if necessary
  337. const source = texture.source;
  338. let webglTextures = _sources.get( source );
  339. if ( webglTextures === undefined ) {
  340. webglTextures = {};
  341. _sources.set( source, webglTextures );
  342. }
  343. // check if there is already a WebGLTexture object for the given texture parameters
  344. const textureCacheKey = getTextureCacheKey( texture );
  345. if ( textureCacheKey !== textureProperties.__cacheKey ) {
  346. // if not, create a new instance of WebGLTexture
  347. if ( webglTextures[ textureCacheKey ] === undefined ) {
  348. // create new entry
  349. webglTextures[ textureCacheKey ] = {
  350. texture: _gl.createTexture(),
  351. usedTimes: 0
  352. };
  353. info.memory.textures ++;
  354. // when a new instance of WebGLTexture was created, a texture upload is required
  355. // even if the image contents are identical
  356. forceUpload = true;
  357. }
  358. webglTextures[ textureCacheKey ].usedTimes ++;
  359. // every time the texture cache key changes, it's necessary to check if an instance of
  360. // WebGLTexture can be deleted in order to avoid a memory leak.
  361. const webglTexture = webglTextures[ textureProperties.__cacheKey ];
  362. if ( webglTexture !== undefined ) {
  363. webglTextures[ textureProperties.__cacheKey ].usedTimes --;
  364. if ( webglTexture.usedTimes === 0 ) {
  365. deleteTexture( texture );
  366. }
  367. }
  368. // store references to cache key and WebGLTexture object
  369. textureProperties.__cacheKey = textureCacheKey;
  370. textureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture;
  371. }
  372. return forceUpload;
  373. }
  374. function uploadTexture( textureProperties, texture, slot ) {
  375. let textureType = _gl.TEXTURE_2D;
  376. if ( texture.isDataTexture2DArray ) textureType = _gl.TEXTURE_2D_ARRAY;
  377. if ( texture.isDataTexture3D ) textureType = _gl.TEXTURE_3D;
  378. const forceUpload = initTexture( textureProperties, texture );
  379. const source = texture.source;
  380. state.activeTexture( _gl.TEXTURE0 + slot );
  381. state.bindTexture( textureType, textureProperties.__webglTexture );
  382. if ( source.version !== source.__currentVersion || forceUpload === true ) {
  383. _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
  384. _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
  385. _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
  386. _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, _gl.NONE );
  387. const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo( texture.image ) === false;
  388. let image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize );
  389. image = verifyColorSpace( texture, image );
  390. const supportsMips = isPowerOfTwo( image ) || isWebGL2,
  391. glFormat = utils.convert( texture.format, texture.encoding );
  392. let glType = utils.convert( texture.type ),
  393. glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding, texture.isVideoTexture );
  394. setTextureParameters( textureType, texture, supportsMips );
  395. let mipmap;
  396. const mipmaps = texture.mipmaps;
  397. const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true );
  398. const allocateMemory = ( textureProperties.__version === undefined );
  399. const levels = getMipLevels( texture, image, supportsMips );
  400. if ( texture.isDepthTexture ) {
  401. // populate depth texture with dummy data
  402. glInternalFormat = _gl.DEPTH_COMPONENT;
  403. if ( isWebGL2 ) {
  404. if ( texture.type === FloatType ) {
  405. glInternalFormat = _gl.DEPTH_COMPONENT32F;
  406. } else if ( texture.type === UnsignedIntType ) {
  407. glInternalFormat = _gl.DEPTH_COMPONENT24;
  408. } else if ( texture.type === UnsignedInt248Type ) {
  409. glInternalFormat = _gl.DEPTH24_STENCIL8;
  410. } else {
  411. glInternalFormat = _gl.DEPTH_COMPONENT16; // WebGL2 requires sized internalformat for glTexImage2D
  412. }
  413. } else {
  414. if ( texture.type === FloatType ) {
  415. console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' );
  416. }
  417. }
  418. // validation checks for WebGL 1
  419. if ( texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) {
  420. // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
  421. // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT
  422. // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
  423. if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) {
  424. console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' );
  425. texture.type = UnsignedShortType;
  426. glType = utils.convert( texture.type );
  427. }
  428. }
  429. if ( texture.format === DepthStencilFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) {
  430. // Depth stencil textures need the DEPTH_STENCIL internal format
  431. // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
  432. glInternalFormat = _gl.DEPTH_STENCIL;
  433. // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are
  434. // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL.
  435. // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/)
  436. if ( texture.type !== UnsignedInt248Type ) {
  437. console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' );
  438. texture.type = UnsignedInt248Type;
  439. glType = utils.convert( texture.type );
  440. }
  441. }
  442. //
  443. if ( useTexStorage && allocateMemory ) {
  444. state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height );
  445. } else {
  446. state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
  447. }
  448. } else if ( texture.isDataTexture ) {
  449. // use manually created mipmaps if available
  450. // if there are no manual mipmaps
  451. // set 0 level mipmap and then use GL to generate other mipmap levels
  452. if ( mipmaps.length > 0 && supportsMips ) {
  453. if ( useTexStorage && allocateMemory ) {
  454. state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );
  455. }
  456. for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
  457. mipmap = mipmaps[ i ];
  458. if ( useTexStorage ) {
  459. state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
  460. } else {
  461. state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
  462. }
  463. }
  464. texture.generateMipmaps = false;
  465. } else {
  466. if ( useTexStorage ) {
  467. if ( allocateMemory ) {
  468. state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );
  469. }
  470. state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data );
  471. } else {
  472. state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );
  473. }
  474. }
  475. } else if ( texture.isCompressedTexture ) {
  476. if ( useTexStorage && allocateMemory ) {
  477. state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );
  478. }
  479. for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
  480. mipmap = mipmaps[ i ];
  481. if ( texture.format !== RGBAFormat ) {
  482. if ( glFormat !== null ) {
  483. if ( useTexStorage ) {
  484. state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );
  485. } else {
  486. state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
  487. }
  488. } else {
  489. console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );
  490. }
  491. } else {
  492. if ( useTexStorage ) {
  493. state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
  494. } else {
  495. state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
  496. }
  497. }
  498. }
  499. } else if ( texture.isDataTexture2DArray ) {
  500. if ( useTexStorage ) {
  501. if ( allocateMemory ) {
  502. state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth );
  503. }
  504. state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );
  505. } else {
  506. state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
  507. }
  508. } else if ( texture.isDataTexture3D ) {
  509. if ( useTexStorage ) {
  510. if ( allocateMemory ) {
  511. state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth );
  512. }
  513. state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );
  514. } else {
  515. state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );
  516. }
  517. } else if ( texture.isFramebufferTexture ) {
  518. if ( useTexStorage && allocateMemory ) {
  519. state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );
  520. } else {
  521. state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
  522. }
  523. } else {
  524. // regular Texture (image, video, canvas)
  525. // use manually created mipmaps if available
  526. // if there are no manual mipmaps
  527. // set 0 level mipmap and then use GL to generate other mipmap levels
  528. if ( mipmaps.length > 0 && supportsMips ) {
  529. if ( useTexStorage && allocateMemory ) {
  530. state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );
  531. }
  532. for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {
  533. mipmap = mipmaps[ i ];
  534. if ( useTexStorage ) {
  535. state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap );
  536. } else {
  537. state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap );
  538. }
  539. }
  540. texture.generateMipmaps = false;
  541. } else {
  542. if ( useTexStorage ) {
  543. if ( allocateMemory ) {
  544. state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );
  545. }
  546. state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image );
  547. } else {
  548. state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image );
  549. }
  550. }
  551. }
  552. if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
  553. generateMipmap( textureType );
  554. }
  555. source.__currentVersion = source.version;
  556. if ( texture.onUpdate ) texture.onUpdate( texture );
  557. }
  558. textureProperties.__version = texture.version;
  559. }
  560. function uploadCubeTexture( textureProperties, texture, slot ) {
  561. if ( texture.image.length !== 6 ) return;
  562. const forceUpload = initTexture( textureProperties, texture );
  563. const source = texture.source;
  564. state.activeTexture( _gl.TEXTURE0 + slot );
  565. state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
  566. if ( source.version !== source.__currentVersion || forceUpload === true ) {
  567. _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
  568. _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
  569. _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
  570. _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, _gl.NONE );
  571. const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture );
  572. const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
  573. const cubeImage = [];
  574. for ( let i = 0; i < 6; i ++ ) {
  575. if ( ! isCompressed && ! isDataTexture ) {
  576. cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize );
  577. } else {
  578. cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
  579. }
  580. cubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] );
  581. }
  582. const image = cubeImage[ 0 ],
  583. supportsMips = isPowerOfTwo( image ) || isWebGL2,
  584. glFormat = utils.convert( texture.format, texture.encoding ),
  585. glType = utils.convert( texture.type ),
  586. glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
  587. const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true );
  588. const allocateMemory = ( textureProperties.__version === undefined );
  589. let levels = getMipLevels( texture, image, supportsMips );
  590. setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips );
  591. let mipmaps;
  592. if ( isCompressed ) {
  593. if ( useTexStorage && allocateMemory ) {
  594. state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height );
  595. }
  596. for ( let i = 0; i < 6; i ++ ) {
  597. mipmaps = cubeImage[ i ].mipmaps;
  598. for ( let j = 0; j < mipmaps.length; j ++ ) {
  599. const mipmap = mipmaps[ j ];
  600. if ( texture.format !== RGBAFormat ) {
  601. if ( glFormat !== null ) {
  602. if ( useTexStorage ) {
  603. state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );
  604. } else {
  605. state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
  606. }
  607. } else {
  608. console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );
  609. }
  610. } else {
  611. if ( useTexStorage ) {
  612. state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
  613. } else {
  614. state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
  615. }
  616. }
  617. }
  618. }
  619. } else {
  620. mipmaps = texture.mipmaps;
  621. if ( useTexStorage && allocateMemory ) {
  622. // TODO: Uniformly handle mipmap definitions
  623. // Normal textures and compressed cube textures define base level + mips with their mipmap array
  624. // Uncompressed cube textures use their mipmap array only for mips (no base level)
  625. if ( mipmaps.length > 0 ) levels ++;
  626. state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height );
  627. }
  628. for ( let i = 0; i < 6; i ++ ) {
  629. if ( isDataTexture ) {
  630. if ( useTexStorage ) {
  631. state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data );
  632. } else {
  633. state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
  634. }
  635. for ( let j = 0; j < mipmaps.length; j ++ ) {
  636. const mipmap = mipmaps[ j ];
  637. const mipmapImage = mipmap.image[ i ].image;
  638. if ( useTexStorage ) {
  639. state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data );
  640. } else {
  641. state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );
  642. }
  643. }
  644. } else {
  645. if ( useTexStorage ) {
  646. state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] );
  647. } else {
  648. state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );
  649. }
  650. for ( let j = 0; j < mipmaps.length; j ++ ) {
  651. const mipmap = mipmaps[ j ];
  652. if ( useTexStorage ) {
  653. state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] );
  654. } else {
  655. state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );
  656. }
  657. }
  658. }
  659. }
  660. }
  661. if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
  662. // We assume images for cube map have the same size.
  663. generateMipmap( _gl.TEXTURE_CUBE_MAP );
  664. }
  665. source.__currentVersion = source.version;
  666. if ( texture.onUpdate ) texture.onUpdate( texture );
  667. }
  668. textureProperties.__version = texture.version;
  669. }
  670. // Render targets
  671. // Setup storage for target texture and bind it to correct framebuffer
  672. function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget ) {
  673. const glFormat = utils.convert( texture.format, texture.encoding );
  674. const glType = utils.convert( texture.type );
  675. const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
  676. const renderTargetProperties = properties.get( renderTarget );
  677. if ( ! renderTargetProperties.__hasExternalTextures ) {
  678. if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) {
  679. state.texImage3D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, renderTarget.depth, 0, glFormat, glType, null );
  680. } else {
  681. state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
  682. }
  683. }
  684. state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
  685. if ( useMultisampledRTT( renderTarget ) ) {
  686. multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) );
  687. } else {
  688. _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0 );
  689. }
  690. state.bindFramebuffer( _gl.FRAMEBUFFER, null );
  691. }
  692. // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
  693. function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {
  694. _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
  695. if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
  696. let glInternalFormat = _gl.DEPTH_COMPONENT16;
  697. if ( isMultisample || useMultisampledRTT( renderTarget ) ) {
  698. const depthTexture = renderTarget.depthTexture;
  699. if ( depthTexture && depthTexture.isDepthTexture ) {
  700. if ( depthTexture.type === FloatType ) {
  701. glInternalFormat = _gl.DEPTH_COMPONENT32F;
  702. } else if ( depthTexture.type === UnsignedIntType ) {
  703. glInternalFormat = _gl.DEPTH_COMPONENT24;
  704. }
  705. }
  706. const samples = getRenderTargetSamples( renderTarget );
  707. if ( useMultisampledRTT( renderTarget ) ) {
  708. multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
  709. } else {
  710. _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
  711. }
  712. } else {
  713. _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );
  714. }
  715. _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
  716. } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
  717. const samples = getRenderTargetSamples( renderTarget );
  718. if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) {
  719. _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height );
  720. } else if ( useMultisampledRTT( renderTarget ) ) {
  721. multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height );
  722. } else {
  723. _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
  724. }
  725. _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
  726. } else {
  727. // Use the first texture for MRT so far
  728. const texture = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture[ 0 ] : renderTarget.texture;
  729. const glFormat = utils.convert( texture.format, texture.encoding );
  730. const glType = utils.convert( texture.type );
  731. const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
  732. const samples = getRenderTargetSamples( renderTarget );
  733. if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) {
  734. _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
  735. } else if ( useMultisampledRTT( renderTarget ) ) {
  736. multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
  737. } else {
  738. _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );
  739. }
  740. }
  741. _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
  742. }
  743. // Setup resources for a Depth Texture for a FBO (needs an extension)
  744. function setupDepthTexture( framebuffer, renderTarget ) {
  745. const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );
  746. if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );
  747. state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
  748. if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {
  749. throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );
  750. }
  751. // upload an empty depth texture with framebuffer size
  752. if ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||
  753. renderTarget.depthTexture.image.width !== renderTarget.width ||
  754. renderTarget.depthTexture.image.height !== renderTarget.height ) {
  755. renderTarget.depthTexture.image.width = renderTarget.width;
  756. renderTarget.depthTexture.image.height = renderTarget.height;
  757. renderTarget.depthTexture.needsUpdate = true;
  758. }
  759. setTexture2D( renderTarget.depthTexture, 0 );
  760. const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;
  761. const samples = getRenderTargetSamples( renderTarget );
  762. if ( renderTarget.depthTexture.format === DepthFormat ) {
  763. if ( useMultisampledRTT( renderTarget ) ) {
  764. multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );
  765. } else {
  766. _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
  767. }
  768. } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {
  769. if ( useMultisampledRTT( renderTarget ) ) {
  770. multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );
  771. } else {
  772. _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
  773. }
  774. } else {
  775. throw new Error( 'Unknown depthTexture format' );
  776. }
  777. }
  778. // Setup GL resources for a non-texture depth buffer
  779. function setupDepthRenderbuffer( renderTarget ) {
  780. const renderTargetProperties = properties.get( renderTarget );
  781. const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
  782. if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) {
  783. if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );
  784. setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );
  785. } else {
  786. if ( isCube ) {
  787. renderTargetProperties.__webglDepthbuffer = [];
  788. for ( let i = 0; i < 6; i ++ ) {
  789. state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );
  790. renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
  791. setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );
  792. }
  793. } else {
  794. state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
  795. renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
  796. setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );
  797. }
  798. }
  799. state.bindFramebuffer( _gl.FRAMEBUFFER, null );
  800. }
  801. // rebind framebuffer with external textures
  802. function rebindTextures( renderTarget, colorTexture, depthTexture ) {
  803. const renderTargetProperties = properties.get( renderTarget );
  804. if ( colorTexture !== undefined ) {
  805. setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D );
  806. }
  807. if ( depthTexture !== undefined ) {
  808. setupDepthRenderbuffer( renderTarget );
  809. }
  810. }
  811. // Set up GL resources for the render target
  812. function setupRenderTarget( renderTarget ) {
  813. const texture = renderTarget.texture;
  814. const renderTargetProperties = properties.get( renderTarget );
  815. const textureProperties = properties.get( texture );
  816. renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
  817. if ( renderTarget.isWebGLMultipleRenderTargets !== true ) {
  818. if ( textureProperties.__webglTexture === undefined ) {
  819. textureProperties.__webglTexture = _gl.createTexture();
  820. }
  821. textureProperties.__version = texture.version;
  822. info.memory.textures ++;
  823. }
  824. const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
  825. const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true );
  826. const isRenderTarget3D = texture.isDataTexture3D || texture.isDataTexture2DArray;
  827. const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;
  828. // Setup framebuffer
  829. if ( isCube ) {
  830. renderTargetProperties.__webglFramebuffer = [];
  831. for ( let i = 0; i < 6; i ++ ) {
  832. renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();
  833. }
  834. } else {
  835. renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();
  836. if ( isMultipleRenderTargets ) {
  837. if ( capabilities.drawBuffers ) {
  838. const textures = renderTarget.texture;
  839. for ( let i = 0, il = textures.length; i < il; i ++ ) {
  840. const attachmentProperties = properties.get( textures[ i ] );
  841. if ( attachmentProperties.__webglTexture === undefined ) {
  842. attachmentProperties.__webglTexture = _gl.createTexture();
  843. info.memory.textures ++;
  844. }
  845. }
  846. } else {
  847. console.warn( 'THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension.' );
  848. }
  849. } else if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) {
  850. renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
  851. renderTargetProperties.__webglColorRenderbuffer = _gl.createRenderbuffer();
  852. _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer );
  853. const glFormat = utils.convert( texture.format, texture.encoding );
  854. const glType = utils.convert( texture.type );
  855. const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding );
  856. const samples = getRenderTargetSamples( renderTarget );
  857. _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
  858. state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
  859. _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer );
  860. _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
  861. if ( renderTarget.depthBuffer ) {
  862. renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
  863. setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );
  864. }
  865. state.bindFramebuffer( _gl.FRAMEBUFFER, null );
  866. }
  867. }
  868. // Setup color buffer
  869. if ( isCube ) {
  870. state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
  871. setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips );
  872. for ( let i = 0; i < 6; i ++ ) {
  873. setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
  874. }
  875. if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
  876. generateMipmap( _gl.TEXTURE_CUBE_MAP );
  877. }
  878. state.unbindTexture();
  879. } else if ( isMultipleRenderTargets ) {
  880. const textures = renderTarget.texture;
  881. for ( let i = 0, il = textures.length; i < il; i ++ ) {
  882. const attachment = textures[ i ];
  883. const attachmentProperties = properties.get( attachment );
  884. state.bindTexture( _gl.TEXTURE_2D, attachmentProperties.__webglTexture );
  885. setTextureParameters( _gl.TEXTURE_2D, attachment, supportsMips );
  886. setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D );
  887. if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) {
  888. generateMipmap( _gl.TEXTURE_2D );
  889. }
  890. }
  891. state.unbindTexture();
  892. } else {
  893. let glTextureType = _gl.TEXTURE_2D;
  894. if ( isRenderTarget3D ) {
  895. // Render targets containing layers, i.e: Texture 3D and 2d arrays
  896. if ( isWebGL2 ) {
  897. const isTexture3D = texture.isDataTexture3D;
  898. glTextureType = isTexture3D ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY;
  899. } else {
  900. console.warn( 'THREE.DataTexture3D and THREE.DataTexture2DArray only supported with WebGL2.' );
  901. }
  902. }
  903. state.bindTexture( glTextureType, textureProperties.__webglTexture );
  904. setTextureParameters( glTextureType, texture, supportsMips );
  905. setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType );
  906. if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
  907. generateMipmap( glTextureType );
  908. }
  909. state.unbindTexture();
  910. }
  911. // Setup depth and stencil buffers
  912. if ( renderTarget.depthBuffer ) {
  913. setupDepthRenderbuffer( renderTarget );
  914. }
  915. }
  916. function updateRenderTargetMipmap( renderTarget ) {
  917. const supportsMips = isPowerOfTwo( renderTarget ) || isWebGL2;
  918. const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ];
  919. for ( let i = 0, il = textures.length; i < il; i ++ ) {
  920. const texture = textures[ i ];
  921. if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) {
  922. const target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;
  923. const webglTexture = properties.get( texture ).__webglTexture;
  924. state.bindTexture( target, webglTexture );
  925. generateMipmap( target );
  926. state.unbindTexture();
  927. }
  928. }
  929. }
  930. function updateMultisampleRenderTarget( renderTarget ) {
  931. if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) {
  932. const width = renderTarget.width;
  933. const height = renderTarget.height;
  934. let mask = _gl.COLOR_BUFFER_BIT;
  935. const invalidationArray = [ _gl.COLOR_ATTACHMENT0 ];
  936. const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;
  937. if ( renderTarget.depthBuffer ) {
  938. invalidationArray.push( depthStyle );
  939. }
  940. const renderTargetProperties = properties.get( renderTarget );
  941. const ignoreDepthValues = ( renderTargetProperties.__ignoreDepthValues !== undefined ) ? renderTargetProperties.__ignoreDepthValues : true;
  942. if ( ignoreDepthValues === false ) {
  943. if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT;
  944. if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT;
  945. }
  946. state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
  947. state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
  948. if ( ignoreDepthValues === true ) {
  949. _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, [ depthStyle ] );
  950. _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] );
  951. }
  952. _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST );
  953. _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArray );
  954. state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null );
  955. state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
  956. }
  957. }
  958. function getRenderTargetSamples( renderTarget ) {
  959. return Math.min( maxSamples, renderTarget.samples );
  960. }
  961. function useMultisampledRTT( renderTarget ) {
  962. const renderTargetProperties = properties.get( renderTarget );
  963. return isWebGL2 && renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false;
  964. }
  965. function updateVideoTexture( texture ) {
  966. const frame = info.render.frame;
  967. // Check the last frame we updated the VideoTexture
  968. if ( _videoTextures.get( texture ) !== frame ) {
  969. _videoTextures.set( texture, frame );
  970. texture.update();
  971. }
  972. }
  973. function verifyColorSpace( texture, image ) {
  974. const encoding = texture.encoding;
  975. const format = texture.format;
  976. const type = texture.type;
  977. if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image;
  978. if ( encoding !== LinearEncoding ) {
  979. // sRGB
  980. if ( encoding === sRGBEncoding ) {
  981. if ( isWebGL2 === false ) {
  982. // in WebGL 1, try to use EXT_sRGB extension and unsized formats
  983. if ( extensions.has( 'EXT_sRGB' ) === true && format === RGBAFormat ) {
  984. texture.format = _SRGBAFormat;
  985. // it's not possible to generate mips in WebGL 1 with this extension
  986. texture.minFilter = LinearFilter;
  987. texture.generateMipmaps = false;
  988. } else {
  989. // slow fallback (CPU decode)
  990. image = ImageUtils.sRGBToLinear( image );
  991. }
  992. } else {
  993. // in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format
  994. if ( format !== RGBAFormat || type !== UnsignedByteType ) {
  995. console.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' );
  996. }
  997. }
  998. } else {
  999. console.error( 'THREE.WebGLTextures: Unsupported texture encoding:', encoding );
  1000. }
  1001. }
  1002. return image;
  1003. }
  1004. // backwards compatibility
  1005. let warnedTexture2D = false;
  1006. let warnedTextureCube = false;
  1007. function safeSetTexture2D( texture, slot ) {
  1008. if ( texture.isWebGLRenderTarget ) {
  1009. if ( warnedTexture2D === false ) {
  1010. console.warn( 'THREE.WebGLTextures.safeSetTexture2D: don\'t use render targets as textures. Use their .texture property instead.' );
  1011. warnedTexture2D = true;
  1012. }
  1013. texture = texture.texture;
  1014. }
  1015. setTexture2D( texture, slot );
  1016. }
  1017. function safeSetTextureCube( texture, slot ) {
  1018. if ( texture.isWebGLCubeRenderTarget ) {
  1019. if ( warnedTextureCube === false ) {
  1020. console.warn( 'THREE.WebGLTextures.safeSetTextureCube: don\'t use cube render targets as textures. Use their .texture property instead.' );
  1021. warnedTextureCube = true;
  1022. }
  1023. texture = texture.texture;
  1024. }
  1025. setTextureCube( texture, slot );
  1026. }
  1027. //
  1028. this.allocateTextureUnit = allocateTextureUnit;
  1029. this.resetTextureUnits = resetTextureUnits;
  1030. this.setTexture2D = setTexture2D;
  1031. this.setTexture2DArray = setTexture2DArray;
  1032. this.setTexture3D = setTexture3D;
  1033. this.setTextureCube = setTextureCube;
  1034. this.rebindTextures = rebindTextures;
  1035. this.setupRenderTarget = setupRenderTarget;
  1036. this.updateRenderTargetMipmap = updateRenderTargetMipmap;
  1037. this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
  1038. this.setupDepthRenderbuffer = setupDepthRenderbuffer;
  1039. this.setupFrameBufferTexture = setupFrameBufferTexture;
  1040. this.useMultisampledRTT = useMultisampledRTT;
  1041. this.safeSetTexture2D = safeSetTexture2D;
  1042. this.safeSetTextureCube = safeSetTextureCube;
  1043. }
  1044. export { WebGLTextures };