WebGLRenderer.js 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489
  1. import {
  2. REVISION,
  3. BackSide,
  4. FrontSide,
  5. DoubleSide,
  6. RGBAFormat,
  7. HalfFloatType,
  8. FloatType,
  9. UnsignedByteType,
  10. NoToneMapping,
  11. LinearMipmapLinearFilter,
  12. SRGBColorSpace,
  13. LinearSRGBColorSpace,
  14. sRGBEncoding,
  15. LinearEncoding,
  16. RGBAIntegerFormat,
  17. RGIntegerFormat,
  18. RedIntegerFormat,
  19. UnsignedIntType,
  20. UnsignedShortType,
  21. UnsignedInt248Type,
  22. UnsignedShort4444Type,
  23. UnsignedShort5551Type,
  24. WebGLCoordinateSystem,
  25. DisplayP3ColorSpace,
  26. LinearDisplayP3ColorSpace
  27. } from '../constants.js';
  28. import { Color } from '../math/Color.js';
  29. import { Frustum } from '../math/Frustum.js';
  30. import { Matrix4 } from '../math/Matrix4.js';
  31. import { Vector2 } from '../math/Vector2.js';
  32. import { Vector3 } from '../math/Vector3.js';
  33. import { Vector4 } from '../math/Vector4.js';
  34. import { floorPowerOfTwo } from '../math/MathUtils.js';
  35. import { WebGLAnimation } from './webgl/WebGLAnimation.js';
  36. import { WebGLAttributes } from './webgl/WebGLAttributes.js';
  37. import { WebGLBackground } from './webgl/WebGLBackground.js';
  38. import { WebGLBindingStates } from './webgl/WebGLBindingStates.js';
  39. import { WebGLBufferRenderer } from './webgl/WebGLBufferRenderer.js';
  40. import { WebGLCapabilities } from './webgl/WebGLCapabilities.js';
  41. import { WebGLClipping } from './webgl/WebGLClipping.js';
  42. import { WebGLCubeMaps } from './webgl/WebGLCubeMaps.js';
  43. import { WebGLCubeUVMaps } from './webgl/WebGLCubeUVMaps.js';
  44. import { WebGLExtensions } from './webgl/WebGLExtensions.js';
  45. import { WebGLGeometries } from './webgl/WebGLGeometries.js';
  46. import { WebGLIndexedBufferRenderer } from './webgl/WebGLIndexedBufferRenderer.js';
  47. import { WebGLInfo } from './webgl/WebGLInfo.js';
  48. import { WebGLMorphtargets } from './webgl/WebGLMorphtargets.js';
  49. import { WebGLObjects } from './webgl/WebGLObjects.js';
  50. import { WebGLPrograms } from './webgl/WebGLPrograms.js';
  51. import { WebGLProperties } from './webgl/WebGLProperties.js';
  52. import { WebGLRenderLists } from './webgl/WebGLRenderLists.js';
  53. import { WebGLRenderStates } from './webgl/WebGLRenderStates.js';
  54. import { WebGLRenderTarget } from './WebGLRenderTarget.js';
  55. import { WebGLShadowMap } from './webgl/WebGLShadowMap.js';
  56. import { WebGLState } from './webgl/WebGLState.js';
  57. import { WebGLTextures } from './webgl/WebGLTextures.js';
  58. import { WebGLUniforms } from './webgl/WebGLUniforms.js';
  59. import { WebGLUtils } from './webgl/WebGLUtils.js';
  60. import { WebXRManager } from './webxr/WebXRManager.js';
  61. import { WebGLMaterials } from './webgl/WebGLMaterials.js';
  62. import { WebGLUniformsGroups } from './webgl/WebGLUniformsGroups.js';
  63. import { createCanvasElement } from '../utils.js';
  64. import { ColorManagement } from '../math/ColorManagement.js';
  65. class WebGLRenderer {
  66. constructor( parameters = {} ) {
  67. const {
  68. canvas = createCanvasElement(),
  69. context = null,
  70. depth = true,
  71. stencil = true,
  72. alpha = false,
  73. antialias = false,
  74. premultipliedAlpha = true,
  75. preserveDrawingBuffer = false,
  76. powerPreference = 'default',
  77. failIfMajorPerformanceCaveat = false,
  78. } = parameters;
  79. this.isWebGLRenderer = true;
  80. let _alpha;
  81. if ( context !== null ) {
  82. _alpha = context.getContextAttributes().alpha;
  83. } else {
  84. _alpha = alpha;
  85. }
  86. const uintClearColor = new Uint32Array( 4 );
  87. const intClearColor = new Int32Array( 4 );
  88. let currentRenderList = null;
  89. let currentRenderState = null;
  90. // render() can be called from within a callback triggered by another render.
  91. // We track this so that the nested render call gets its list and state isolated from the parent render call.
  92. const renderListStack = [];
  93. const renderStateStack = [];
  94. // public properties
  95. this.domElement = canvas;
  96. // Debug configuration container
  97. this.debug = {
  98. /**
  99. * Enables error checking and reporting when shader programs are being compiled
  100. * @type {boolean}
  101. */
  102. checkShaderErrors: true,
  103. /**
  104. * Callback for custom error reporting.
  105. * @type {?Function}
  106. */
  107. onShaderError: null
  108. };
  109. // clearing
  110. this.autoClear = true;
  111. this.autoClearColor = true;
  112. this.autoClearDepth = true;
  113. this.autoClearStencil = true;
  114. // scene graph
  115. this.sortObjects = true;
  116. // user-defined clipping
  117. this.clippingPlanes = [];
  118. this.localClippingEnabled = false;
  119. // physically based shading
  120. this._outputColorSpace = SRGBColorSpace;
  121. // physical lights
  122. this._useLegacyLights = false;
  123. // tone mapping
  124. this.toneMapping = NoToneMapping;
  125. this.toneMappingExposure = 1.0;
  126. // internal properties
  127. const _this = this;
  128. let _isContextLost = false;
  129. // internal state cache
  130. let _currentActiveCubeFace = 0;
  131. let _currentActiveMipmapLevel = 0;
  132. let _currentRenderTarget = null;
  133. let _currentMaterialId = - 1;
  134. let _currentCamera = null;
  135. const _currentViewport = new Vector4();
  136. const _currentScissor = new Vector4();
  137. let _currentScissorTest = null;
  138. const _currentClearColor = new Color( 0x000000 );
  139. let _currentClearAlpha = 0;
  140. //
  141. let _width = canvas.width;
  142. let _height = canvas.height;
  143. let _pixelRatio = 1;
  144. let _opaqueSort = null;
  145. let _transparentSort = null;
  146. const _viewport = new Vector4( 0, 0, _width, _height );
  147. const _scissor = new Vector4( 0, 0, _width, _height );
  148. let _scissorTest = false;
  149. // frustum
  150. const _frustum = new Frustum();
  151. // clipping
  152. let _clippingEnabled = false;
  153. let _localClippingEnabled = false;
  154. // transmission
  155. let _transmissionRenderTarget = null;
  156. // camera matrices cache
  157. const _projScreenMatrix = new Matrix4();
  158. const _vector2 = new Vector2();
  159. const _vector3 = new Vector3();
  160. const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true };
  161. function getTargetPixelRatio() {
  162. return _currentRenderTarget === null ? _pixelRatio : 1;
  163. }
  164. // initialize
  165. let _gl = context;
  166. function getContext( contextNames, contextAttributes ) {
  167. for ( let i = 0; i < contextNames.length; i ++ ) {
  168. const contextName = contextNames[ i ];
  169. const context = canvas.getContext( contextName, contextAttributes );
  170. if ( context !== null ) return context;
  171. }
  172. return null;
  173. }
  174. try {
  175. const contextAttributes = {
  176. alpha: true,
  177. depth,
  178. stencil,
  179. antialias,
  180. premultipliedAlpha,
  181. preserveDrawingBuffer,
  182. powerPreference,
  183. failIfMajorPerformanceCaveat,
  184. };
  185. // OffscreenCanvas does not have setAttribute, see #22811
  186. if ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` );
  187. // event listeners must be registered before WebGL context is created, see #12753
  188. canvas.addEventListener( 'webglcontextlost', onContextLost, false );
  189. canvas.addEventListener( 'webglcontextrestored', onContextRestore, false );
  190. canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false );
  191. if ( _gl === null ) {
  192. const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ];
  193. if ( _this.isWebGL1Renderer === true ) {
  194. contextNames.shift();
  195. }
  196. _gl = getContext( contextNames, contextAttributes );
  197. if ( _gl === null ) {
  198. if ( getContext( contextNames ) ) {
  199. throw new Error( 'Error creating WebGL context with your selected attributes.' );
  200. } else {
  201. throw new Error( 'Error creating WebGL context.' );
  202. }
  203. }
  204. }
  205. if ( typeof WebGLRenderingContext !== 'undefined' && _gl instanceof WebGLRenderingContext ) { // @deprecated, r153
  206. console.warn( 'THREE.WebGLRenderer: WebGL 1 support was deprecated in r153 and will be removed in r163.' );
  207. }
  208. // Some experimental-webgl implementations do not have getShaderPrecisionFormat
  209. if ( _gl.getShaderPrecisionFormat === undefined ) {
  210. _gl.getShaderPrecisionFormat = function () {
  211. return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 };
  212. };
  213. }
  214. } catch ( error ) {
  215. console.error( 'THREE.WebGLRenderer: ' + error.message );
  216. throw error;
  217. }
  218. let extensions, capabilities, state, info;
  219. let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects;
  220. let programCache, materials, renderLists, renderStates, clipping, shadowMap;
  221. let background, morphtargets, bufferRenderer, indexedBufferRenderer;
  222. let utils, bindingStates, uniformsGroups;
  223. function initGLContext() {
  224. extensions = new WebGLExtensions( _gl );
  225. capabilities = new WebGLCapabilities( _gl, extensions, parameters );
  226. extensions.init( capabilities );
  227. utils = new WebGLUtils( _gl, extensions, capabilities );
  228. state = new WebGLState( _gl, extensions, capabilities );
  229. info = new WebGLInfo( _gl );
  230. properties = new WebGLProperties();
  231. textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
  232. cubemaps = new WebGLCubeMaps( _this );
  233. cubeuvmaps = new WebGLCubeUVMaps( _this );
  234. attributes = new WebGLAttributes( _gl, capabilities );
  235. bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities );
  236. geometries = new WebGLGeometries( _gl, attributes, info, bindingStates );
  237. objects = new WebGLObjects( _gl, geometries, attributes, info );
  238. morphtargets = new WebGLMorphtargets( _gl, capabilities, textures );
  239. clipping = new WebGLClipping( properties );
  240. programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping );
  241. materials = new WebGLMaterials( _this, properties );
  242. renderLists = new WebGLRenderLists();
  243. renderStates = new WebGLRenderStates( extensions, capabilities );
  244. background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha );
  245. shadowMap = new WebGLShadowMap( _this, objects, capabilities );
  246. uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state );
  247. bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities );
  248. indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities );
  249. info.programs = programCache.programs;
  250. _this.capabilities = capabilities;
  251. _this.extensions = extensions;
  252. _this.properties = properties;
  253. _this.renderLists = renderLists;
  254. _this.shadowMap = shadowMap;
  255. _this.state = state;
  256. _this.info = info;
  257. }
  258. initGLContext();
  259. // xr
  260. const xr = new WebXRManager( _this, _gl );
  261. this.xr = xr;
  262. // API
  263. this.getContext = function () {
  264. return _gl;
  265. };
  266. this.getContextAttributes = function () {
  267. return _gl.getContextAttributes();
  268. };
  269. this.forceContextLoss = function () {
  270. const extension = extensions.get( 'WEBGL_lose_context' );
  271. if ( extension ) extension.loseContext();
  272. };
  273. this.forceContextRestore = function () {
  274. const extension = extensions.get( 'WEBGL_lose_context' );
  275. if ( extension ) extension.restoreContext();
  276. };
  277. this.getPixelRatio = function () {
  278. return _pixelRatio;
  279. };
  280. this.setPixelRatio = function ( value ) {
  281. if ( value === undefined ) return;
  282. _pixelRatio = value;
  283. this.setSize( _width, _height, false );
  284. };
  285. this.getSize = function ( target ) {
  286. return target.set( _width, _height );
  287. };
  288. this.setSize = function ( width, height, updateStyle = true ) {
  289. if ( xr.isPresenting ) {
  290. console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
  291. return;
  292. }
  293. _width = width;
  294. _height = height;
  295. canvas.width = Math.floor( width * _pixelRatio );
  296. canvas.height = Math.floor( height * _pixelRatio );
  297. if ( updateStyle === true ) {
  298. canvas.style.width = width + 'px';
  299. canvas.style.height = height + 'px';
  300. }
  301. this.setViewport( 0, 0, width, height );
  302. };
  303. this.getDrawingBufferSize = function ( target ) {
  304. return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();
  305. };
  306. this.setDrawingBufferSize = function ( width, height, pixelRatio ) {
  307. _width = width;
  308. _height = height;
  309. _pixelRatio = pixelRatio;
  310. canvas.width = Math.floor( width * pixelRatio );
  311. canvas.height = Math.floor( height * pixelRatio );
  312. this.setViewport( 0, 0, width, height );
  313. };
  314. this.getCurrentViewport = function ( target ) {
  315. return target.copy( _currentViewport );
  316. };
  317. this.getViewport = function ( target ) {
  318. return target.copy( _viewport );
  319. };
  320. this.setViewport = function ( x, y, width, height ) {
  321. if ( x.isVector4 ) {
  322. _viewport.set( x.x, x.y, x.z, x.w );
  323. } else {
  324. _viewport.set( x, y, width, height );
  325. }
  326. state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
  327. };
  328. this.getScissor = function ( target ) {
  329. return target.copy( _scissor );
  330. };
  331. this.setScissor = function ( x, y, width, height ) {
  332. if ( x.isVector4 ) {
  333. _scissor.set( x.x, x.y, x.z, x.w );
  334. } else {
  335. _scissor.set( x, y, width, height );
  336. }
  337. state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() );
  338. };
  339. this.getScissorTest = function () {
  340. return _scissorTest;
  341. };
  342. this.setScissorTest = function ( boolean ) {
  343. state.setScissorTest( _scissorTest = boolean );
  344. };
  345. this.setOpaqueSort = function ( method ) {
  346. _opaqueSort = method;
  347. };
  348. this.setTransparentSort = function ( method ) {
  349. _transparentSort = method;
  350. };
  351. // Clearing
  352. this.getClearColor = function ( target ) {
  353. return target.copy( background.getClearColor() );
  354. };
  355. this.setClearColor = function () {
  356. background.setClearColor.apply( background, arguments );
  357. };
  358. this.getClearAlpha = function () {
  359. return background.getClearAlpha();
  360. };
  361. this.setClearAlpha = function () {
  362. background.setClearAlpha.apply( background, arguments );
  363. };
  364. this.clear = function ( color = true, depth = true, stencil = true ) {
  365. let bits = 0;
  366. if ( color ) {
  367. // check if we're trying to clear an integer target
  368. let isIntegerFormat = false;
  369. if ( _currentRenderTarget !== null ) {
  370. const targetFormat = _currentRenderTarget.texture.format;
  371. isIntegerFormat = targetFormat === RGBAIntegerFormat ||
  372. targetFormat === RGIntegerFormat ||
  373. targetFormat === RedIntegerFormat;
  374. }
  375. // use the appropriate clear functions to clear the target if it's a signed
  376. // or unsigned integer target
  377. if ( isIntegerFormat ) {
  378. const targetType = _currentRenderTarget.texture.type;
  379. const isUnsignedType = targetType === UnsignedByteType ||
  380. targetType === UnsignedIntType ||
  381. targetType === UnsignedShortType ||
  382. targetType === UnsignedInt248Type ||
  383. targetType === UnsignedShort4444Type ||
  384. targetType === UnsignedShort5551Type;
  385. const clearColor = background.getClearColor();
  386. const a = background.getClearAlpha();
  387. const r = clearColor.r;
  388. const g = clearColor.g;
  389. const b = clearColor.b;
  390. if ( isUnsignedType ) {
  391. uintClearColor[ 0 ] = r;
  392. uintClearColor[ 1 ] = g;
  393. uintClearColor[ 2 ] = b;
  394. uintClearColor[ 3 ] = a;
  395. _gl.clearBufferuiv( _gl.COLOR, 0, uintClearColor );
  396. } else {
  397. intClearColor[ 0 ] = r;
  398. intClearColor[ 1 ] = g;
  399. intClearColor[ 2 ] = b;
  400. intClearColor[ 3 ] = a;
  401. _gl.clearBufferiv( _gl.COLOR, 0, intClearColor );
  402. }
  403. } else {
  404. bits |= _gl.COLOR_BUFFER_BIT;
  405. }
  406. }
  407. if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT;
  408. if ( stencil ) {
  409. bits |= _gl.STENCIL_BUFFER_BIT;
  410. this.state.buffers.stencil.setMask( 0xffffffff );
  411. }
  412. _gl.clear( bits );
  413. };
  414. this.clearColor = function () {
  415. this.clear( true, false, false );
  416. };
  417. this.clearDepth = function () {
  418. this.clear( false, true, false );
  419. };
  420. this.clearStencil = function () {
  421. this.clear( false, false, true );
  422. };
  423. //
  424. this.dispose = function () {
  425. canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
  426. canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
  427. canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false );
  428. renderLists.dispose();
  429. renderStates.dispose();
  430. properties.dispose();
  431. cubemaps.dispose();
  432. cubeuvmaps.dispose();
  433. objects.dispose();
  434. bindingStates.dispose();
  435. uniformsGroups.dispose();
  436. programCache.dispose();
  437. xr.dispose();
  438. xr.removeEventListener( 'sessionstart', onXRSessionStart );
  439. xr.removeEventListener( 'sessionend', onXRSessionEnd );
  440. if ( _transmissionRenderTarget ) {
  441. _transmissionRenderTarget.dispose();
  442. _transmissionRenderTarget = null;
  443. }
  444. animation.stop();
  445. };
  446. // Events
  447. function onContextLost( event ) {
  448. event.preventDefault();
  449. console.log( 'THREE.WebGLRenderer: Context Lost.' );
  450. _isContextLost = true;
  451. }
  452. function onContextRestore( /* event */ ) {
  453. console.log( 'THREE.WebGLRenderer: Context Restored.' );
  454. _isContextLost = false;
  455. const infoAutoReset = info.autoReset;
  456. const shadowMapEnabled = shadowMap.enabled;
  457. const shadowMapAutoUpdate = shadowMap.autoUpdate;
  458. const shadowMapNeedsUpdate = shadowMap.needsUpdate;
  459. const shadowMapType = shadowMap.type;
  460. initGLContext();
  461. info.autoReset = infoAutoReset;
  462. shadowMap.enabled = shadowMapEnabled;
  463. shadowMap.autoUpdate = shadowMapAutoUpdate;
  464. shadowMap.needsUpdate = shadowMapNeedsUpdate;
  465. shadowMap.type = shadowMapType;
  466. }
  467. function onContextCreationError( event ) {
  468. console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage );
  469. }
  470. function onMaterialDispose( event ) {
  471. const material = event.target;
  472. material.removeEventListener( 'dispose', onMaterialDispose );
  473. deallocateMaterial( material );
  474. }
  475. // Buffer deallocation
  476. function deallocateMaterial( material ) {
  477. releaseMaterialProgramReferences( material );
  478. properties.remove( material );
  479. }
  480. function releaseMaterialProgramReferences( material ) {
  481. const programs = properties.get( material ).programs;
  482. if ( programs !== undefined ) {
  483. programs.forEach( function ( program ) {
  484. programCache.releaseProgram( program );
  485. } );
  486. if ( material.isShaderMaterial ) {
  487. programCache.releaseShaderCache( material );
  488. }
  489. }
  490. }
  491. // Buffer rendering
  492. this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) {
  493. if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)
  494. const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );
  495. const program = setProgram( camera, scene, geometry, material, object );
  496. state.setMaterial( material, frontFaceCW );
  497. //
  498. let index = geometry.index;
  499. let rangeFactor = 1;
  500. if ( material.wireframe === true ) {
  501. index = geometries.getWireframeAttribute( geometry );
  502. if ( index === undefined ) return;
  503. rangeFactor = 2;
  504. }
  505. //
  506. const drawRange = geometry.drawRange;
  507. const position = geometry.attributes.position;
  508. let drawStart = drawRange.start * rangeFactor;
  509. let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor;
  510. if ( group !== null ) {
  511. drawStart = Math.max( drawStart, group.start * rangeFactor );
  512. drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor );
  513. }
  514. if ( index !== null ) {
  515. drawStart = Math.max( drawStart, 0 );
  516. drawEnd = Math.min( drawEnd, index.count );
  517. } else if ( position !== undefined && position !== null ) {
  518. drawStart = Math.max( drawStart, 0 );
  519. drawEnd = Math.min( drawEnd, position.count );
  520. }
  521. const drawCount = drawEnd - drawStart;
  522. if ( drawCount < 0 || drawCount === Infinity ) return;
  523. //
  524. bindingStates.setup( object, material, program, geometry, index );
  525. let attribute;
  526. let renderer = bufferRenderer;
  527. if ( index !== null ) {
  528. attribute = attributes.get( index );
  529. renderer = indexedBufferRenderer;
  530. renderer.setIndex( attribute );
  531. }
  532. //
  533. if ( object.isMesh ) {
  534. if ( material.wireframe === true ) {
  535. state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
  536. renderer.setMode( _gl.LINES );
  537. } else {
  538. renderer.setMode( _gl.TRIANGLES );
  539. }
  540. } else if ( object.isLine ) {
  541. let lineWidth = material.linewidth;
  542. if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material
  543. state.setLineWidth( lineWidth * getTargetPixelRatio() );
  544. if ( object.isLineSegments ) {
  545. renderer.setMode( _gl.LINES );
  546. } else if ( object.isLineLoop ) {
  547. renderer.setMode( _gl.LINE_LOOP );
  548. } else {
  549. renderer.setMode( _gl.LINE_STRIP );
  550. }
  551. } else if ( object.isPoints ) {
  552. renderer.setMode( _gl.POINTS );
  553. } else if ( object.isSprite ) {
  554. renderer.setMode( _gl.TRIANGLES );
  555. }
  556. if ( object.isInstancedMesh ) {
  557. renderer.renderInstances( drawStart, drawCount, object.count );
  558. } else if ( geometry.isInstancedBufferGeometry ) {
  559. const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity;
  560. const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount );
  561. renderer.renderInstances( drawStart, drawCount, instanceCount );
  562. } else {
  563. renderer.render( drawStart, drawCount );
  564. }
  565. };
  566. // Compile
  567. this.compile = function ( scene, camera ) {
  568. function prepare( material, scene, object ) {
  569. if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {
  570. material.side = BackSide;
  571. material.needsUpdate = true;
  572. getProgram( material, scene, object );
  573. material.side = FrontSide;
  574. material.needsUpdate = true;
  575. getProgram( material, scene, object );
  576. material.side = DoubleSide;
  577. } else {
  578. getProgram( material, scene, object );
  579. }
  580. }
  581. currentRenderState = renderStates.get( scene );
  582. currentRenderState.init();
  583. renderStateStack.push( currentRenderState );
  584. scene.traverseVisible( function ( object ) {
  585. if ( object.isLight && object.layers.test( camera.layers ) ) {
  586. currentRenderState.pushLight( object );
  587. if ( object.castShadow ) {
  588. currentRenderState.pushShadow( object );
  589. }
  590. }
  591. } );
  592. currentRenderState.setupLights( _this._useLegacyLights );
  593. scene.traverse( function ( object ) {
  594. const material = object.material;
  595. if ( material ) {
  596. if ( Array.isArray( material ) ) {
  597. for ( let i = 0; i < material.length; i ++ ) {
  598. const material2 = material[ i ];
  599. prepare( material2, scene, object );
  600. }
  601. } else {
  602. prepare( material, scene, object );
  603. }
  604. }
  605. } );
  606. renderStateStack.pop();
  607. currentRenderState = null;
  608. };
  609. // Animation Loop
  610. let onAnimationFrameCallback = null;
  611. function onAnimationFrame( time ) {
  612. if ( onAnimationFrameCallback ) onAnimationFrameCallback( time );
  613. }
  614. function onXRSessionStart() {
  615. animation.stop();
  616. }
  617. function onXRSessionEnd() {
  618. animation.start();
  619. }
  620. const animation = new WebGLAnimation();
  621. animation.setAnimationLoop( onAnimationFrame );
  622. if ( typeof self !== 'undefined' ) animation.setContext( self );
  623. this.setAnimationLoop = function ( callback ) {
  624. onAnimationFrameCallback = callback;
  625. xr.setAnimationLoop( callback );
  626. ( callback === null ) ? animation.stop() : animation.start();
  627. };
  628. xr.addEventListener( 'sessionstart', onXRSessionStart );
  629. xr.addEventListener( 'sessionend', onXRSessionEnd );
  630. // Rendering
  631. this.render = function ( scene, camera ) {
  632. if ( camera !== undefined && camera.isCamera !== true ) {
  633. console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
  634. return;
  635. }
  636. if ( _isContextLost === true ) return;
  637. // update scene graph
  638. if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();
  639. // update camera matrices and frustum
  640. if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();
  641. if ( xr.enabled === true && xr.isPresenting === true ) {
  642. if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera );
  643. camera = xr.getCamera(); // use XR camera for rendering
  644. }
  645. //
  646. if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget );
  647. currentRenderState = renderStates.get( scene, renderStateStack.length );
  648. currentRenderState.init();
  649. renderStateStack.push( currentRenderState );
  650. _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
  651. _frustum.setFromProjectionMatrix( _projScreenMatrix );
  652. _localClippingEnabled = this.localClippingEnabled;
  653. _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled );
  654. currentRenderList = renderLists.get( scene, renderListStack.length );
  655. currentRenderList.init();
  656. renderListStack.push( currentRenderList );
  657. projectObject( scene, camera, 0, _this.sortObjects );
  658. currentRenderList.finish();
  659. if ( _this.sortObjects === true ) {
  660. currentRenderList.sort( _opaqueSort, _transparentSort );
  661. }
  662. //
  663. this.info.render.frame ++;
  664. if ( _clippingEnabled === true ) clipping.beginShadows();
  665. const shadowsArray = currentRenderState.state.shadowsArray;
  666. shadowMap.render( shadowsArray, scene, camera );
  667. if ( _clippingEnabled === true ) clipping.endShadows();
  668. //
  669. if ( this.info.autoReset === true ) this.info.reset();
  670. //
  671. background.render( currentRenderList, scene );
  672. // render scene
  673. currentRenderState.setupLights( _this._useLegacyLights );
  674. if ( camera.isArrayCamera ) {
  675. const cameras = camera.cameras;
  676. for ( let i = 0, l = cameras.length; i < l; i ++ ) {
  677. const camera2 = cameras[ i ];
  678. renderScene( currentRenderList, scene, camera2, camera2.viewport );
  679. }
  680. } else {
  681. renderScene( currentRenderList, scene, camera );
  682. }
  683. //
  684. if ( _currentRenderTarget !== null ) {
  685. // resolve multisample renderbuffers to a single-sample texture if necessary
  686. textures.updateMultisampleRenderTarget( _currentRenderTarget );
  687. // Generate mipmap if we're using any kind of mipmap filtering
  688. textures.updateRenderTargetMipmap( _currentRenderTarget );
  689. }
  690. //
  691. if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );
  692. // _gl.finish();
  693. bindingStates.resetDefaultState();
  694. _currentMaterialId = - 1;
  695. _currentCamera = null;
  696. renderStateStack.pop();
  697. if ( renderStateStack.length > 0 ) {
  698. currentRenderState = renderStateStack[ renderStateStack.length - 1 ];
  699. } else {
  700. currentRenderState = null;
  701. }
  702. renderListStack.pop();
  703. if ( renderListStack.length > 0 ) {
  704. currentRenderList = renderListStack[ renderListStack.length - 1 ];
  705. } else {
  706. currentRenderList = null;
  707. }
  708. };
  709. function projectObject( object, camera, groupOrder, sortObjects ) {
  710. if ( object.visible === false ) return;
  711. const visible = object.layers.test( camera.layers );
  712. if ( visible ) {
  713. if ( object.isGroup ) {
  714. groupOrder = object.renderOrder;
  715. } else if ( object.isLOD ) {
  716. if ( object.autoUpdate === true ) object.update( camera );
  717. } else if ( object.isLight ) {
  718. currentRenderState.pushLight( object );
  719. if ( object.castShadow ) {
  720. currentRenderState.pushShadow( object );
  721. }
  722. } else if ( object.isSprite ) {
  723. if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {
  724. if ( sortObjects ) {
  725. _vector3.setFromMatrixPosition( object.matrixWorld )
  726. .applyMatrix4( _projScreenMatrix );
  727. }
  728. const geometry = objects.update( object );
  729. const material = object.material;
  730. if ( material.visible ) {
  731. currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
  732. }
  733. }
  734. } else if ( object.isMesh || object.isLine || object.isPoints ) {
  735. if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {
  736. const geometry = objects.update( object );
  737. const material = object.material;
  738. if ( sortObjects ) {
  739. if ( object.boundingSphere !== undefined ) {
  740. if ( object.boundingSphere === null ) object.computeBoundingSphere();
  741. _vector3.copy( object.boundingSphere.center );
  742. } else {
  743. if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
  744. _vector3.copy( geometry.boundingSphere.center );
  745. }
  746. _vector3
  747. .applyMatrix4( object.matrixWorld )
  748. .applyMatrix4( _projScreenMatrix );
  749. }
  750. if ( Array.isArray( material ) ) {
  751. const groups = geometry.groups;
  752. for ( let i = 0, l = groups.length; i < l; i ++ ) {
  753. const group = groups[ i ];
  754. const groupMaterial = material[ group.materialIndex ];
  755. if ( groupMaterial && groupMaterial.visible ) {
  756. currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group );
  757. }
  758. }
  759. } else if ( material.visible ) {
  760. currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null );
  761. }
  762. }
  763. }
  764. }
  765. const children = object.children;
  766. for ( let i = 0, l = children.length; i < l; i ++ ) {
  767. projectObject( children[ i ], camera, groupOrder, sortObjects );
  768. }
  769. }
  770. function renderScene( currentRenderList, scene, camera, viewport ) {
  771. const opaqueObjects = currentRenderList.opaque;
  772. const transmissiveObjects = currentRenderList.transmissive;
  773. const transparentObjects = currentRenderList.transparent;
  774. currentRenderState.setupLightsView( camera );
  775. if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );
  776. if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera );
  777. if ( viewport ) state.viewport( _currentViewport.copy( viewport ) );
  778. if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );
  779. if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera );
  780. if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera );
  781. // Ensure depth buffer writing is enabled so it can be cleared on next render
  782. state.buffers.depth.setTest( true );
  783. state.buffers.depth.setMask( true );
  784. state.buffers.color.setMask( true );
  785. state.setPolygonOffset( false );
  786. }
  787. function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) {
  788. const isWebGL2 = capabilities.isWebGL2;
  789. if ( _transmissionRenderTarget === null ) {
  790. _transmissionRenderTarget = new WebGLRenderTarget( 1, 1, {
  791. generateMipmaps: true,
  792. type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType,
  793. minFilter: LinearMipmapLinearFilter,
  794. samples: ( isWebGL2 ) ? 4 : 0
  795. } );
  796. // debug
  797. /*
  798. const geometry = new PlaneGeometry();
  799. const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } );
  800. const mesh = new Mesh( geometry, material );
  801. scene.add( mesh );
  802. */
  803. }
  804. _this.getDrawingBufferSize( _vector2 );
  805. if ( isWebGL2 ) {
  806. _transmissionRenderTarget.setSize( _vector2.x, _vector2.y );
  807. } else {
  808. _transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) );
  809. }
  810. //
  811. const currentRenderTarget = _this.getRenderTarget();
  812. _this.setRenderTarget( _transmissionRenderTarget );
  813. _this.getClearColor( _currentClearColor );
  814. _currentClearAlpha = _this.getClearAlpha();
  815. if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 );
  816. _this.clear();
  817. // Turn off the features which can affect the frag color for opaque objects pass.
  818. // Otherwise they are applied twice in opaque objects pass and transmission objects pass.
  819. const currentToneMapping = _this.toneMapping;
  820. _this.toneMapping = NoToneMapping;
  821. renderObjects( opaqueObjects, scene, camera );
  822. textures.updateMultisampleRenderTarget( _transmissionRenderTarget );
  823. textures.updateRenderTargetMipmap( _transmissionRenderTarget );
  824. let renderTargetNeedsUpdate = false;
  825. for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) {
  826. const renderItem = transmissiveObjects[ i ];
  827. const object = renderItem.object;
  828. const geometry = renderItem.geometry;
  829. const material = renderItem.material;
  830. const group = renderItem.group;
  831. if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) {
  832. const currentSide = material.side;
  833. material.side = BackSide;
  834. material.needsUpdate = true;
  835. renderObject( object, scene, camera, geometry, material, group );
  836. material.side = currentSide;
  837. material.needsUpdate = true;
  838. renderTargetNeedsUpdate = true;
  839. }
  840. }
  841. if ( renderTargetNeedsUpdate === true ) {
  842. textures.updateMultisampleRenderTarget( _transmissionRenderTarget );
  843. textures.updateRenderTargetMipmap( _transmissionRenderTarget );
  844. }
  845. _this.setRenderTarget( currentRenderTarget );
  846. _this.setClearColor( _currentClearColor, _currentClearAlpha );
  847. _this.toneMapping = currentToneMapping;
  848. }
  849. function renderObjects( renderList, scene, camera ) {
  850. const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;
  851. for ( let i = 0, l = renderList.length; i < l; i ++ ) {
  852. const renderItem = renderList[ i ];
  853. const object = renderItem.object;
  854. const geometry = renderItem.geometry;
  855. const material = overrideMaterial === null ? renderItem.material : overrideMaterial;
  856. const group = renderItem.group;
  857. if ( object.layers.test( camera.layers ) ) {
  858. renderObject( object, scene, camera, geometry, material, group );
  859. }
  860. }
  861. }
  862. function renderObject( object, scene, camera, geometry, material, group ) {
  863. object.onBeforeRender( _this, scene, camera, geometry, material, group );
  864. object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
  865. object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
  866. material.onBeforeRender( _this, scene, camera, geometry, object, group );
  867. if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {
  868. material.side = BackSide;
  869. material.needsUpdate = true;
  870. _this.renderBufferDirect( camera, scene, geometry, material, object, group );
  871. material.side = FrontSide;
  872. material.needsUpdate = true;
  873. _this.renderBufferDirect( camera, scene, geometry, material, object, group );
  874. material.side = DoubleSide;
  875. } else {
  876. _this.renderBufferDirect( camera, scene, geometry, material, object, group );
  877. }
  878. object.onAfterRender( _this, scene, camera, geometry, material, group );
  879. }
  880. function getProgram( material, scene, object ) {
  881. if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
  882. const materialProperties = properties.get( material );
  883. const lights = currentRenderState.state.lights;
  884. const shadowsArray = currentRenderState.state.shadowsArray;
  885. const lightsStateVersion = lights.state.version;
  886. const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
  887. const programCacheKey = programCache.getProgramCacheKey( parameters );
  888. let programs = materialProperties.programs;
  889. // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change
  890. materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;
  891. materialProperties.fog = scene.fog;
  892. materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment );
  893. if ( programs === undefined ) {
  894. // new material
  895. material.addEventListener( 'dispose', onMaterialDispose );
  896. programs = new Map();
  897. materialProperties.programs = programs;
  898. }
  899. let program = programs.get( programCacheKey );
  900. if ( program !== undefined ) {
  901. // early out if program and light state is identical
  902. if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) {
  903. updateCommonMaterialProperties( material, parameters );
  904. return program;
  905. }
  906. } else {
  907. parameters.uniforms = programCache.getUniforms( material );
  908. material.onBuild( object, parameters, _this );
  909. material.onBeforeCompile( parameters, _this );
  910. program = programCache.acquireProgram( parameters, programCacheKey );
  911. programs.set( programCacheKey, program );
  912. materialProperties.uniforms = parameters.uniforms;
  913. }
  914. const uniforms = materialProperties.uniforms;
  915. if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) {
  916. uniforms.clippingPlanes = clipping.uniform;
  917. }
  918. updateCommonMaterialProperties( material, parameters );
  919. // store the light setup it was created for
  920. materialProperties.needsLights = materialNeedsLights( material );
  921. materialProperties.lightsStateVersion = lightsStateVersion;
  922. if ( materialProperties.needsLights ) {
  923. // wire up the material to this renderer's lighting state
  924. uniforms.ambientLightColor.value = lights.state.ambient;
  925. uniforms.lightProbe.value = lights.state.probe;
  926. uniforms.directionalLights.value = lights.state.directional;
  927. uniforms.directionalLightShadows.value = lights.state.directionalShadow;
  928. uniforms.spotLights.value = lights.state.spot;
  929. uniforms.spotLightShadows.value = lights.state.spotShadow;
  930. uniforms.rectAreaLights.value = lights.state.rectArea;
  931. uniforms.ltc_1.value = lights.state.rectAreaLTC1;
  932. uniforms.ltc_2.value = lights.state.rectAreaLTC2;
  933. uniforms.pointLights.value = lights.state.point;
  934. uniforms.pointLightShadows.value = lights.state.pointShadow;
  935. uniforms.hemisphereLights.value = lights.state.hemi;
  936. uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
  937. uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
  938. uniforms.spotShadowMap.value = lights.state.spotShadowMap;
  939. uniforms.spotLightMatrix.value = lights.state.spotLightMatrix;
  940. uniforms.spotLightMap.value = lights.state.spotLightMap;
  941. uniforms.pointShadowMap.value = lights.state.pointShadowMap;
  942. uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
  943. // TODO (abelnation): add area lights shadow info to uniforms
  944. }
  945. const progUniforms = program.getUniforms();
  946. const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );
  947. materialProperties.currentProgram = program;
  948. materialProperties.uniformsList = uniformsList;
  949. return program;
  950. }
  951. function updateCommonMaterialProperties( material, parameters ) {
  952. const materialProperties = properties.get( material );
  953. materialProperties.outputColorSpace = parameters.outputColorSpace;
  954. materialProperties.instancing = parameters.instancing;
  955. materialProperties.instancingColor = parameters.instancingColor;
  956. materialProperties.skinning = parameters.skinning;
  957. materialProperties.morphTargets = parameters.morphTargets;
  958. materialProperties.morphNormals = parameters.morphNormals;
  959. materialProperties.morphColors = parameters.morphColors;
  960. materialProperties.morphTargetsCount = parameters.morphTargetsCount;
  961. materialProperties.numClippingPlanes = parameters.numClippingPlanes;
  962. materialProperties.numIntersection = parameters.numClipIntersection;
  963. materialProperties.vertexAlphas = parameters.vertexAlphas;
  964. materialProperties.vertexTangents = parameters.vertexTangents;
  965. materialProperties.toneMapping = parameters.toneMapping;
  966. }
  967. function setProgram( camera, scene, geometry, material, object ) {
  968. if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
  969. textures.resetTextureUnits();
  970. const fog = scene.fog;
  971. const environment = material.isMeshStandardMaterial ? scene.environment : null;
  972. const colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace );
  973. const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
  974. const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4;
  975. const vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 );
  976. const morphTargets = !! geometry.morphAttributes.position;
  977. const morphNormals = !! geometry.morphAttributes.normal;
  978. const morphColors = !! geometry.morphAttributes.color;
  979. let toneMapping = NoToneMapping;
  980. if ( material.toneMapped ) {
  981. if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) {
  982. toneMapping = _this.toneMapping;
  983. }
  984. }
  985. const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
  986. const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
  987. const materialProperties = properties.get( material );
  988. const lights = currentRenderState.state.lights;
  989. if ( _clippingEnabled === true ) {
  990. if ( _localClippingEnabled === true || camera !== _currentCamera ) {
  991. const useCache =
  992. camera === _currentCamera &&
  993. material.id === _currentMaterialId;
  994. // we might want to call this function with some ClippingGroup
  995. // object instead of the material, once it becomes feasible
  996. // (#8465, #8379)
  997. clipping.setState( material, camera, useCache );
  998. }
  999. }
  1000. //
  1001. let needsProgramChange = false;
  1002. if ( material.version === materialProperties.__version ) {
  1003. if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {
  1004. needsProgramChange = true;
  1005. } else if ( materialProperties.outputColorSpace !== colorSpace ) {
  1006. needsProgramChange = true;
  1007. } else if ( object.isInstancedMesh && materialProperties.instancing === false ) {
  1008. needsProgramChange = true;
  1009. } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) {
  1010. needsProgramChange = true;
  1011. } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) {
  1012. needsProgramChange = true;
  1013. } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) {
  1014. needsProgramChange = true;
  1015. } else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) {
  1016. needsProgramChange = true;
  1017. } else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) {
  1018. needsProgramChange = true;
  1019. } else if ( materialProperties.envMap !== envMap ) {
  1020. needsProgramChange = true;
  1021. } else if ( material.fog === true && materialProperties.fog !== fog ) {
  1022. needsProgramChange = true;
  1023. } else if ( materialProperties.numClippingPlanes !== undefined &&
  1024. ( materialProperties.numClippingPlanes !== clipping.numPlanes ||
  1025. materialProperties.numIntersection !== clipping.numIntersection ) ) {
  1026. needsProgramChange = true;
  1027. } else if ( materialProperties.vertexAlphas !== vertexAlphas ) {
  1028. needsProgramChange = true;
  1029. } else if ( materialProperties.vertexTangents !== vertexTangents ) {
  1030. needsProgramChange = true;
  1031. } else if ( materialProperties.morphTargets !== morphTargets ) {
  1032. needsProgramChange = true;
  1033. } else if ( materialProperties.morphNormals !== morphNormals ) {
  1034. needsProgramChange = true;
  1035. } else if ( materialProperties.morphColors !== morphColors ) {
  1036. needsProgramChange = true;
  1037. } else if ( materialProperties.toneMapping !== toneMapping ) {
  1038. needsProgramChange = true;
  1039. } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) {
  1040. needsProgramChange = true;
  1041. }
  1042. } else {
  1043. needsProgramChange = true;
  1044. materialProperties.__version = material.version;
  1045. }
  1046. //
  1047. let program = materialProperties.currentProgram;
  1048. if ( needsProgramChange === true ) {
  1049. program = getProgram( material, scene, object );
  1050. }
  1051. let refreshProgram = false;
  1052. let refreshMaterial = false;
  1053. let refreshLights = false;
  1054. const p_uniforms = program.getUniforms(),
  1055. m_uniforms = materialProperties.uniforms;
  1056. if ( state.useProgram( program.program ) ) {
  1057. refreshProgram = true;
  1058. refreshMaterial = true;
  1059. refreshLights = true;
  1060. }
  1061. if ( material.id !== _currentMaterialId ) {
  1062. _currentMaterialId = material.id;
  1063. refreshMaterial = true;
  1064. }
  1065. if ( refreshProgram || _currentCamera !== camera ) {
  1066. // common camera uniforms
  1067. p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
  1068. p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
  1069. const uCamPos = p_uniforms.map.cameraPosition;
  1070. if ( uCamPos !== undefined ) {
  1071. uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) );
  1072. }
  1073. if ( capabilities.logarithmicDepthBuffer ) {
  1074. p_uniforms.setValue( _gl, 'logDepthBufFC',
  1075. 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
  1076. }
  1077. // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067
  1078. if ( material.isMeshPhongMaterial ||
  1079. material.isMeshToonMaterial ||
  1080. material.isMeshLambertMaterial ||
  1081. material.isMeshBasicMaterial ||
  1082. material.isMeshStandardMaterial ||
  1083. material.isShaderMaterial ) {
  1084. p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );
  1085. }
  1086. if ( _currentCamera !== camera ) {
  1087. _currentCamera = camera;
  1088. // lighting uniforms depend on the camera so enforce an update
  1089. // now, in case this material supports lights - or later, when
  1090. // the next material that does gets activated:
  1091. refreshMaterial = true; // set to true on material change
  1092. refreshLights = true; // remains set until update done
  1093. }
  1094. }
  1095. // skinning and morph target uniforms must be set even if material didn't change
  1096. // auto-setting of texture unit for bone and morph texture must go before other textures
  1097. // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures
  1098. if ( object.isSkinnedMesh ) {
  1099. p_uniforms.setOptional( _gl, object, 'bindMatrix' );
  1100. p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );
  1101. const skeleton = object.skeleton;
  1102. if ( skeleton ) {
  1103. if ( capabilities.floatVertexTextures ) {
  1104. if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture();
  1105. p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );
  1106. p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize );
  1107. } else {
  1108. console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' );
  1109. }
  1110. }
  1111. }
  1112. const morphAttributes = geometry.morphAttributes;
  1113. if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) {
  1114. morphtargets.update( object, geometry, program );
  1115. }
  1116. if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {
  1117. materialProperties.receiveShadow = object.receiveShadow;
  1118. p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );
  1119. }
  1120. // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512
  1121. if ( material.isMeshGouraudMaterial && material.envMap !== null ) {
  1122. m_uniforms.envMap.value = envMap;
  1123. m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1;
  1124. }
  1125. if ( refreshMaterial ) {
  1126. p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );
  1127. if ( materialProperties.needsLights ) {
  1128. // the current material requires lighting info
  1129. // note: all lighting uniforms are always set correctly
  1130. // they simply reference the renderer's state for their
  1131. // values
  1132. //
  1133. // use the current material's .needsUpdate flags to set
  1134. // the GL state when required
  1135. markUniformsLightsNeedsUpdate( m_uniforms, refreshLights );
  1136. }
  1137. // refresh uniforms common to several materials
  1138. if ( fog && material.fog === true ) {
  1139. materials.refreshFogUniforms( m_uniforms, fog );
  1140. }
  1141. materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget );
  1142. WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures );
  1143. }
  1144. if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {
  1145. WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures );
  1146. material.uniformsNeedUpdate = false;
  1147. }
  1148. if ( material.isSpriteMaterial ) {
  1149. p_uniforms.setValue( _gl, 'center', object.center );
  1150. }
  1151. // common matrices
  1152. p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
  1153. p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
  1154. p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );
  1155. // UBOs
  1156. if ( material.isShaderMaterial || material.isRawShaderMaterial ) {
  1157. const groups = material.uniformsGroups;
  1158. for ( let i = 0, l = groups.length; i < l; i ++ ) {
  1159. if ( capabilities.isWebGL2 ) {
  1160. const group = groups[ i ];
  1161. uniformsGroups.update( group, program );
  1162. uniformsGroups.bind( group, program );
  1163. } else {
  1164. console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' );
  1165. }
  1166. }
  1167. }
  1168. return program;
  1169. }
  1170. // If uniforms are marked as clean, they don't need to be loaded to the GPU.
  1171. function markUniformsLightsNeedsUpdate( uniforms, value ) {
  1172. uniforms.ambientLightColor.needsUpdate = value;
  1173. uniforms.lightProbe.needsUpdate = value;
  1174. uniforms.directionalLights.needsUpdate = value;
  1175. uniforms.directionalLightShadows.needsUpdate = value;
  1176. uniforms.pointLights.needsUpdate = value;
  1177. uniforms.pointLightShadows.needsUpdate = value;
  1178. uniforms.spotLights.needsUpdate = value;
  1179. uniforms.spotLightShadows.needsUpdate = value;
  1180. uniforms.rectAreaLights.needsUpdate = value;
  1181. uniforms.hemisphereLights.needsUpdate = value;
  1182. }
  1183. function materialNeedsLights( material ) {
  1184. return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||
  1185. material.isMeshStandardMaterial || material.isShadowMaterial ||
  1186. ( material.isShaderMaterial && material.lights === true );
  1187. }
  1188. this.getActiveCubeFace = function () {
  1189. return _currentActiveCubeFace;
  1190. };
  1191. this.getActiveMipmapLevel = function () {
  1192. return _currentActiveMipmapLevel;
  1193. };
  1194. this.getRenderTarget = function () {
  1195. return _currentRenderTarget;
  1196. };
  1197. this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) {
  1198. properties.get( renderTarget.texture ).__webglTexture = colorTexture;
  1199. properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture;
  1200. const renderTargetProperties = properties.get( renderTarget );
  1201. renderTargetProperties.__hasExternalTextures = true;
  1202. if ( renderTargetProperties.__hasExternalTextures ) {
  1203. renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined;
  1204. if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) {
  1205. // The multisample_render_to_texture extension doesn't work properly if there
  1206. // are midframe flushes and an external depth buffer. Disable use of the extension.
  1207. if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) {
  1208. console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' );
  1209. renderTargetProperties.__useRenderToTexture = false;
  1210. }
  1211. }
  1212. }
  1213. };
  1214. this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) {
  1215. const renderTargetProperties = properties.get( renderTarget );
  1216. renderTargetProperties.__webglFramebuffer = defaultFramebuffer;
  1217. renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined;
  1218. };
  1219. this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {
  1220. _currentRenderTarget = renderTarget;
  1221. _currentActiveCubeFace = activeCubeFace;
  1222. _currentActiveMipmapLevel = activeMipmapLevel;
  1223. let useDefaultFramebuffer = true;
  1224. let framebuffer = null;
  1225. let isCube = false;
  1226. let isRenderTarget3D = false;
  1227. if ( renderTarget ) {
  1228. const renderTargetProperties = properties.get( renderTarget );
  1229. if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) {
  1230. // We need to make sure to rebind the framebuffer.
  1231. state.bindFramebuffer( _gl.FRAMEBUFFER, null );
  1232. useDefaultFramebuffer = false;
  1233. } else if ( renderTargetProperties.__webglFramebuffer === undefined ) {
  1234. textures.setupRenderTarget( renderTarget );
  1235. } else if ( renderTargetProperties.__hasExternalTextures ) {
  1236. // Color and depth texture must be rebound in order for the swapchain to update.
  1237. textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture );
  1238. }
  1239. const texture = renderTarget.texture;
  1240. if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
  1241. isRenderTarget3D = true;
  1242. }
  1243. const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;
  1244. if ( renderTarget.isWebGLCubeRenderTarget ) {
  1245. if ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) {
  1246. framebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ];
  1247. } else {
  1248. framebuffer = __webglFramebuffer[ activeCubeFace ];
  1249. }
  1250. isCube = true;
  1251. } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) {
  1252. framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;
  1253. } else {
  1254. if ( Array.isArray( __webglFramebuffer ) ) {
  1255. framebuffer = __webglFramebuffer[ activeMipmapLevel ];
  1256. } else {
  1257. framebuffer = __webglFramebuffer;
  1258. }
  1259. }
  1260. _currentViewport.copy( renderTarget.viewport );
  1261. _currentScissor.copy( renderTarget.scissor );
  1262. _currentScissorTest = renderTarget.scissorTest;
  1263. } else {
  1264. _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();
  1265. _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();
  1266. _currentScissorTest = _scissorTest;
  1267. }
  1268. const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
  1269. if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) {
  1270. state.drawBuffers( renderTarget, framebuffer );
  1271. }
  1272. state.viewport( _currentViewport );
  1273. state.scissor( _currentScissor );
  1274. state.setScissorTest( _currentScissorTest );
  1275. if ( isCube ) {
  1276. const textureProperties = properties.get( renderTarget.texture );
  1277. _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel );
  1278. } else if ( isRenderTarget3D ) {
  1279. const textureProperties = properties.get( renderTarget.texture );
  1280. const layer = activeCubeFace || 0;
  1281. _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer );
  1282. }
  1283. _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings
  1284. };
  1285. this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {
  1286. if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {
  1287. console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
  1288. return;
  1289. }
  1290. let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
  1291. if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {
  1292. framebuffer = framebuffer[ activeCubeFaceIndex ];
  1293. }
  1294. if ( framebuffer ) {
  1295. state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
  1296. try {
  1297. const texture = renderTarget.texture;
  1298. const textureFormat = texture.format;
  1299. const textureType = texture.type;
  1300. if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {
  1301. console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
  1302. return;
  1303. }
  1304. const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) );
  1305. if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513)
  1306. ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox
  1307. ! halfFloatSupportedByExt ) {
  1308. console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
  1309. return;
  1310. }
  1311. // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
  1312. if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
  1313. _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );
  1314. }
  1315. } finally {
  1316. // restore framebuffer of current render target if necessary
  1317. const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
  1318. state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
  1319. }
  1320. }
  1321. };
  1322. this.copyFramebufferToTexture = function ( position, texture, level = 0 ) {
  1323. const levelScale = Math.pow( 2, - level );
  1324. const width = Math.floor( texture.image.width * levelScale );
  1325. const height = Math.floor( texture.image.height * levelScale );
  1326. textures.setTexture2D( texture, 0 );
  1327. _gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, position.x, position.y, width, height );
  1328. state.unbindTexture();
  1329. };
  1330. this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) {
  1331. const width = srcTexture.image.width;
  1332. const height = srcTexture.image.height;
  1333. const glFormat = utils.convert( dstTexture.format );
  1334. const glType = utils.convert( dstTexture.type );
  1335. textures.setTexture2D( dstTexture, 0 );
  1336. // As another texture upload may have changed pixelStorei
  1337. // parameters, make sure they are correct for the dstTexture
  1338. _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
  1339. _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
  1340. _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
  1341. if ( srcTexture.isDataTexture ) {
  1342. _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data );
  1343. } else {
  1344. if ( srcTexture.isCompressedTexture ) {
  1345. _gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data );
  1346. } else {
  1347. _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image );
  1348. }
  1349. }
  1350. // Generate mipmaps only when copying level 0
  1351. if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D );
  1352. state.unbindTexture();
  1353. };
  1354. this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) {
  1355. if ( _this.isWebGL1Renderer ) {
  1356. console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' );
  1357. return;
  1358. }
  1359. const width = sourceBox.max.x - sourceBox.min.x + 1;
  1360. const height = sourceBox.max.y - sourceBox.min.y + 1;
  1361. const depth = sourceBox.max.z - sourceBox.min.z + 1;
  1362. const glFormat = utils.convert( dstTexture.format );
  1363. const glType = utils.convert( dstTexture.type );
  1364. let glTarget;
  1365. if ( dstTexture.isData3DTexture ) {
  1366. textures.setTexture3D( dstTexture, 0 );
  1367. glTarget = _gl.TEXTURE_3D;
  1368. } else if ( dstTexture.isDataArrayTexture ) {
  1369. textures.setTexture2DArray( dstTexture, 0 );
  1370. glTarget = _gl.TEXTURE_2D_ARRAY;
  1371. } else {
  1372. console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' );
  1373. return;
  1374. }
  1375. _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
  1376. _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
  1377. _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
  1378. const unpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
  1379. const unpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );
  1380. const unpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
  1381. const unpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );
  1382. const unpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );
  1383. const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ 0 ] : srcTexture.image;
  1384. _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );
  1385. _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );
  1386. _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, sourceBox.min.x );
  1387. _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, sourceBox.min.y );
  1388. _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, sourceBox.min.z );
  1389. if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) {
  1390. _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data );
  1391. } else {
  1392. if ( srcTexture.isCompressedArrayTexture ) {
  1393. console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' );
  1394. _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data );
  1395. } else {
  1396. _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image );
  1397. }
  1398. }
  1399. _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, unpackRowLen );
  1400. _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight );
  1401. _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, unpackSkipPixels );
  1402. _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, unpackSkipRows );
  1403. _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, unpackSkipImages );
  1404. // Generate mipmaps only when copying level 0
  1405. if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget );
  1406. state.unbindTexture();
  1407. };
  1408. this.initTexture = function ( texture ) {
  1409. if ( texture.isCubeTexture ) {
  1410. textures.setTextureCube( texture, 0 );
  1411. } else if ( texture.isData3DTexture ) {
  1412. textures.setTexture3D( texture, 0 );
  1413. } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {
  1414. textures.setTexture2DArray( texture, 0 );
  1415. } else {
  1416. textures.setTexture2D( texture, 0 );
  1417. }
  1418. state.unbindTexture();
  1419. };
  1420. this.resetState = function () {
  1421. _currentActiveCubeFace = 0;
  1422. _currentActiveMipmapLevel = 0;
  1423. _currentRenderTarget = null;
  1424. state.reset();
  1425. bindingStates.reset();
  1426. };
  1427. if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
  1428. __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );
  1429. }
  1430. }
  1431. get coordinateSystem() {
  1432. return WebGLCoordinateSystem;
  1433. }
  1434. get outputColorSpace() {
  1435. return this._outputColorSpace;
  1436. }
  1437. set outputColorSpace( colorSpace ) {
  1438. this._outputColorSpace = colorSpace;
  1439. const gl = this.getContext();
  1440. gl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb';
  1441. gl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb';
  1442. }
  1443. get physicallyCorrectLights() { // @deprecated, r150
  1444. console.warn( 'THREE.WebGLRenderer: The property .physicallyCorrectLights has been removed. Set renderer.useLegacyLights instead.' );
  1445. return ! this.useLegacyLights;
  1446. }
  1447. set physicallyCorrectLights( value ) { // @deprecated, r150
  1448. console.warn( 'THREE.WebGLRenderer: The property .physicallyCorrectLights has been removed. Set renderer.useLegacyLights instead.' );
  1449. this.useLegacyLights = ! value;
  1450. }
  1451. get outputEncoding() { // @deprecated, r152
  1452. console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' );
  1453. return this.outputColorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding;
  1454. }
  1455. set outputEncoding( encoding ) { // @deprecated, r152
  1456. console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' );
  1457. this.outputColorSpace = encoding === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace;
  1458. }
  1459. get useLegacyLights() { // @deprecated, r155
  1460. console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' );
  1461. return this._useLegacyLights;
  1462. }
  1463. set useLegacyLights( value ) { // @deprecated, r155
  1464. console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' );
  1465. this._useLegacyLights = value;
  1466. }
  1467. }
  1468. export { WebGLRenderer };