WebGLBackend.js 21 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000
  1. import { WebGLCoordinateSystem } from 'three';
  2. import GLSLNodeBuilder from './nodes/GLSLNodeBuilder.js';
  3. import Backend from '../common/Backend.js';
  4. import WebGLAttributeUtils from './utils/WebGLAttributeUtils.js';
  5. import WebGLState from './utils/WebGLState.js';
  6. import WebGLUtils from './utils/WebGLUtils.js';
  7. import WebGLTextureUtils from './utils/WebGLTextureUtils.js';
  8. import WebGLExtensions from './utils/WebGLExtensions.js';
  9. import WebGLCapabilities from './utils/WebGLCapabilities.js';
  10. import { GLFeatureName } from './utils/WebGLConstants.js';
  11. //
  12. class WebGLBackend extends Backend {
  13. constructor( parameters = {} ) {
  14. super( parameters );
  15. this.isWebGLBackend = true;
  16. }
  17. init( renderer ) {
  18. super.init( renderer );
  19. //
  20. const parameters = this.parameters;
  21. const glContext = ( parameters.context !== undefined ) ? parameters.context : renderer.domElement.getContext( 'webgl2' );
  22. this.gl = glContext;
  23. this.extensions = new WebGLExtensions( this );
  24. this.capabilities = new WebGLCapabilities( this );
  25. this.attributeUtils = new WebGLAttributeUtils( this );
  26. this.textureUtils = new WebGLTextureUtils( this );
  27. this.state = new WebGLState( this );
  28. this.utils = new WebGLUtils( this );
  29. this.extensions.get( 'EXT_color_buffer_float' );
  30. this._currentContext = null;
  31. }
  32. get coordinateSystem() {
  33. return WebGLCoordinateSystem;
  34. }
  35. async getArrayBufferAsync( attribute ) {
  36. return await this.attributeUtils.getArrayBufferAsync( attribute );
  37. }
  38. getContext() {
  39. return this.gl;
  40. }
  41. beginRender( renderContext ) {
  42. const { gl } = this;
  43. const renderContextData = this.get( renderContext );
  44. //
  45. //
  46. renderContextData.previousContext = this._currentContext;
  47. this._currentContext = renderContext;
  48. this._setFramebuffer( renderContext );
  49. this.clear( renderContext.clearColor, renderContext.clearDepth, renderContext.clearStencil, renderContext );
  50. //
  51. if ( renderContext.viewport ) {
  52. this.updateViewport( renderContext );
  53. } else {
  54. gl.viewport( 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight );
  55. }
  56. const occlusionQueryCount = renderContext.occlusionQueryCount;
  57. if ( occlusionQueryCount > 0 ) {
  58. // Get a reference to the array of objects with queries. The renderContextData property
  59. // can be changed by another render pass before the async reading of all previous queries complete
  60. renderContextData.currentOcclusionQueries = renderContextData.occlusionQueries;
  61. renderContextData.currentOcclusionQueryObjects = renderContextData.occlusionQueryObjects;
  62. renderContextData.lastOcclusionObject = null;
  63. renderContextData.occlusionQueries = new Array( occlusionQueryCount );
  64. renderContextData.occlusionQueryObjects = new Array( occlusionQueryCount );
  65. renderContextData.occlusionQueryIndex = 0;
  66. }
  67. }
  68. finishRender( renderContext ) {
  69. const { gl } = this;
  70. const renderContextData = this.get( renderContext );
  71. const previousContext = renderContextData.previousContext;
  72. const textures = renderContext.textures;
  73. if ( textures !== null ) {
  74. for ( let i = 0; i < textures.length; i ++ ) {
  75. const texture = textures[ i ];
  76. if ( texture.generateMipmaps ) {
  77. this.generateMipmaps( texture );
  78. }
  79. }
  80. }
  81. this._currentContext = previousContext;
  82. if ( renderContext.textures !== null && renderContext.renderTarget ) {
  83. const renderTargetContextData = this.get( renderContext.renderTarget );
  84. const { samples } = renderContext.renderTarget;
  85. const fb = renderTargetContextData.framebuffer;
  86. if ( samples > 0 ) {
  87. // TODO For loop support MRT
  88. const msaaFrameBuffer = renderTargetContextData.msaaFrameBuffer;
  89. gl.bindFramebuffer( gl.READ_FRAMEBUFFER, msaaFrameBuffer );
  90. gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb );
  91. gl.blitFramebuffer( 0, 0, renderContext.width, renderContext.height, 0, 0, renderContext.width, renderContext.height, gl.COLOR_BUFFER_BIT, gl.NEAREST );
  92. gl.invalidateFramebuffer( gl.READ_FRAMEBUFFER, renderTargetContextData.invalidationArray );
  93. }
  94. }
  95. if ( previousContext !== null ) {
  96. this._setFramebuffer( previousContext );
  97. if ( previousContext.viewport ) {
  98. this.updateViewport( previousContext );
  99. } else {
  100. const gl = this.gl;
  101. gl.viewport( 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight );
  102. }
  103. }
  104. const occlusionQueryCount = renderContext.occlusionQueryCount;
  105. if ( occlusionQueryCount > 0 ) {
  106. const renderContextData = this.get( renderContext );
  107. if ( occlusionQueryCount > renderContextData.occlusionQueryIndex ) {
  108. const { gl } = this;
  109. gl.endQuery( gl.ANY_SAMPLES_PASSED );
  110. }
  111. this.resolveOccludedAsync( renderContext );
  112. }
  113. }
  114. resolveOccludedAsync( renderContext ) {
  115. const renderContextData = this.get( renderContext );
  116. // handle occlusion query results
  117. const { currentOcclusionQueries, currentOcclusionQueryObjects } = renderContextData;
  118. if ( currentOcclusionQueries && currentOcclusionQueryObjects ) {
  119. const occluded = new WeakSet();
  120. const { gl } = this;
  121. renderContextData.currentOcclusionQueryObjects = null;
  122. renderContextData.currentOcclusionQueries = null;
  123. const check = () => {
  124. let completed = 0;
  125. // check all queries and requeue as appropriate
  126. for ( let i = 0; i < currentOcclusionQueries.length; i ++ ) {
  127. const query = currentOcclusionQueries[ i ];
  128. if ( query === null ) continue;
  129. if ( gl.getQueryParameter( query, gl.QUERY_RESULT_AVAILABLE ) ) {
  130. if ( gl.getQueryParameter( query, gl.QUERY_RESULT ) > 0 ) occluded.add( currentOcclusionQueryObjects[ i ] );
  131. currentOcclusionQueries[ i ] = null;
  132. gl.deleteQuery( query );
  133. completed ++;
  134. }
  135. }
  136. if ( completed < currentOcclusionQueries.length ) {
  137. requestAnimationFrame( check );
  138. } else {
  139. renderContextData.occluded = occluded;
  140. }
  141. };
  142. check();
  143. }
  144. }
  145. isOccluded( renderContext, object ) {
  146. const renderContextData = this.get( renderContext );
  147. return renderContextData.occluded && renderContextData.occluded.has( object );
  148. }
  149. updateViewport( renderContext ) {
  150. const gl = this.gl;
  151. const { x, y, width, height } = renderContext.viewportValue;
  152. gl.viewport( x, y, width, height );
  153. }
  154. clear( color, depth, stencil, descriptor = null ) {
  155. const { gl } = this;
  156. if ( descriptor === null ) {
  157. descriptor = {
  158. textures: null,
  159. clearColorValue: this.getClearColor()
  160. };
  161. }
  162. //
  163. let clear = 0;
  164. if ( color ) clear |= gl.COLOR_BUFFER_BIT;
  165. if ( depth ) clear |= gl.DEPTH_BUFFER_BIT;
  166. if ( stencil ) clear |= gl.STENCIL_BUFFER_BIT;
  167. if ( clear !== 0 ) {
  168. const clearColor = descriptor.clearColorValue;
  169. if ( depth ) this.state.setDepthMask( true );
  170. if ( descriptor.textures === null ) {
  171. gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearColor.a );
  172. gl.clear( clear );
  173. } else {
  174. if ( color ) {
  175. for ( let i = 0; i < descriptor.textures.length; i ++ ) {
  176. gl.clearBufferfv( gl.COLOR, i, [ clearColor.r, clearColor.g, clearColor.b, clearColor.a ] );
  177. }
  178. }
  179. if ( depth && stencil ) {
  180. gl.clearBufferfi( gl.DEPTH_STENCIL, 0, 1, 0 );
  181. } else if ( depth ) {
  182. gl.clearBufferfv( gl.DEPTH, 0, [ 1.0 ] );
  183. } else if ( stencil ) {
  184. gl.clearBufferiv( gl.STENCIL, 0, [ 0 ] );
  185. }
  186. }
  187. }
  188. }
  189. beginCompute( /*computeGroup*/ ) {
  190. console.warn( 'Abstract class.' );
  191. }
  192. compute( /*computeGroup, computeNode, bindings, pipeline*/ ) {
  193. console.warn( 'Abstract class.' );
  194. }
  195. finishCompute( /*computeGroup*/ ) {
  196. console.warn( 'Abstract class.' );
  197. }
  198. draw( renderObject, info ) {
  199. const { pipeline, material, context } = renderObject;
  200. const { programGPU, vaoGPU } = this.get( pipeline );
  201. const { gl, state } = this;
  202. const contextData = this.get( context );
  203. //
  204. const bindings = renderObject.getBindings();
  205. for ( const binding of bindings ) {
  206. const bindingData = this.get( binding );
  207. const index = bindingData.index;
  208. if ( binding.isUniformsGroup || binding.isUniformBuffer ) {
  209. gl.bindBufferBase( gl.UNIFORM_BUFFER, index, bindingData.bufferGPU );
  210. } else if ( binding.isSampledTexture ) {
  211. state.bindTexture( bindingData.glTextureType, bindingData.textureGPU, gl.TEXTURE0 + index );
  212. }
  213. }
  214. state.setMaterial( material );
  215. gl.useProgram( programGPU );
  216. gl.bindVertexArray( vaoGPU );
  217. //
  218. const index = renderObject.getIndex();
  219. const object = renderObject.object;
  220. const geometry = renderObject.geometry;
  221. const drawRange = geometry.drawRange;
  222. const firstVertex = drawRange.start;
  223. //
  224. const lastObject = contextData.lastOcclusionObject;
  225. if ( lastObject !== object && lastObject !== undefined ) {
  226. if ( lastObject !== null && lastObject.occlusionTest === true ) {
  227. gl.endQuery( gl.ANY_SAMPLES_PASSED );
  228. contextData.occlusionQueryIndex ++;
  229. }
  230. if ( object.occlusionTest === true ) {
  231. const query = gl.createQuery();
  232. gl.beginQuery( gl.ANY_SAMPLES_PASSED, query );
  233. contextData.occlusionQueries[ contextData.occlusionQueryIndex ] = query;
  234. contextData.occlusionQueryObjects[ contextData.occlusionQueryIndex ] = object;
  235. }
  236. contextData.lastOcclusionObject = object;
  237. }
  238. //
  239. let mode;
  240. if ( object.isPoints ) mode = gl.POINTS;
  241. else if ( object.isLineSegments ) mode = gl.LINES;
  242. else if ( object.isLine ) mode = gl.LINE_STRIP;
  243. else if ( object.isLineLoop ) mode = gl.LINE_LOOP;
  244. else {
  245. if ( material.wireframe === true ) {
  246. state.setLineWidth( material.wireframeLinewidth * this.renderer.getPixelRatio() );
  247. mode = gl.LINES;
  248. } else {
  249. mode = gl.TRIANGLES;
  250. }
  251. }
  252. //
  253. const instanceCount = this.getInstanceCount( renderObject );
  254. if ( index !== null ) {
  255. const indexData = this.get( index );
  256. const indexCount = ( drawRange.count !== Infinity ) ? drawRange.count : index.count;
  257. if ( instanceCount > 1 ) {
  258. gl.drawElementsInstanced( mode, index.count, indexData.type, firstVertex, instanceCount );
  259. } else {
  260. gl.drawElements( mode, index.count, indexData.type, firstVertex );
  261. }
  262. info.update( object, indexCount, 1 );
  263. } else {
  264. const positionAttribute = geometry.attributes.position;
  265. const vertexCount = ( drawRange.count !== Infinity ) ? drawRange.count : positionAttribute.count;
  266. if ( instanceCount > 1 ) {
  267. gl.drawArraysInstanced( mode, 0, vertexCount, instanceCount );
  268. } else {
  269. gl.drawArrays( mode, 0, vertexCount );
  270. }
  271. //gl.drawArrays( mode, vertexCount, gl.UNSIGNED_SHORT, firstVertex );
  272. info.update( object, vertexCount, 1 );
  273. }
  274. //
  275. gl.bindVertexArray( null );
  276. }
  277. needsRenderUpdate( /*renderObject*/ ) {
  278. return false;
  279. }
  280. getRenderCacheKey( renderObject ) {
  281. return renderObject.id;
  282. }
  283. // textures
  284. createDefaultTexture( texture ) {
  285. this.textureUtils.createDefaultTexture( texture );
  286. }
  287. createTexture( texture, options ) {
  288. this.textureUtils.createTexture( texture, options );
  289. }
  290. updateTexture( texture, options ) {
  291. this.textureUtils.updateTexture( texture, options );
  292. }
  293. generateMipmaps( texture ) {
  294. this.textureUtils.generateMipmaps( texture );
  295. }
  296. destroyTexture( texture ) {
  297. this.textureUtils.destroyTexture( texture );
  298. }
  299. copyTextureToBuffer( texture, x, y, width, height ) {
  300. return this.textureUtils.copyTextureToBuffer( texture, x, y, width, height );
  301. }
  302. createSampler( /*texture*/ ) {
  303. //console.warn( 'Abstract class.' );
  304. }
  305. destroySampler() {}
  306. // node builder
  307. createNodeBuilder( object, renderer, scene = null ) {
  308. return new GLSLNodeBuilder( object, renderer, scene );
  309. }
  310. // program
  311. createProgram( program ) {
  312. const gl = this.gl;
  313. const { stage, code } = program;
  314. const shader = stage === 'vertex' ? gl.createShader( gl.VERTEX_SHADER ) : gl.createShader( gl.FRAGMENT_SHADER );
  315. gl.shaderSource( shader, code );
  316. gl.compileShader( shader );
  317. this.set( program, {
  318. shaderGPU: shader
  319. } );
  320. }
  321. destroyProgram( /*program*/ ) {
  322. console.warn( 'Abstract class.' );
  323. }
  324. createRenderPipeline( renderObject ) {
  325. const gl = this.gl;
  326. const pipeline = renderObject.pipeline;
  327. // Program
  328. const { fragmentProgram, vertexProgram } = pipeline;
  329. const programGPU = gl.createProgram();
  330. const fragmentShader = this.get( fragmentProgram ).shaderGPU;
  331. const vertexShader = this.get( vertexProgram ).shaderGPU;
  332. gl.attachShader( programGPU, fragmentShader );
  333. gl.attachShader( programGPU, vertexShader );
  334. gl.linkProgram( programGPU );
  335. if ( gl.getProgramParameter( programGPU, gl.LINK_STATUS ) === false ) {
  336. console.error( 'THREE.WebGLBackend:', gl.getProgramInfoLog( programGPU ) );
  337. console.error( 'THREE.WebGLBackend:', gl.getShaderInfoLog( fragmentShader ) );
  338. console.error( 'THREE.WebGLBackend:', gl.getShaderInfoLog( vertexShader ) );
  339. }
  340. gl.useProgram( programGPU );
  341. // Bindings
  342. const bindings = renderObject.getBindings();
  343. for ( const binding of bindings ) {
  344. const bindingData = this.get( binding );
  345. const index = bindingData.index;
  346. if ( binding.isUniformsGroup || binding.isUniformBuffer ) {
  347. const location = gl.getUniformBlockIndex( programGPU, binding.name );
  348. gl.uniformBlockBinding( programGPU, location, index );
  349. } else if ( binding.isSampledTexture ) {
  350. const location = gl.getUniformLocation( programGPU, binding.name );
  351. gl.uniform1i( location, index );
  352. }
  353. }
  354. // VAO
  355. const vaoGPU = gl.createVertexArray();
  356. const index = renderObject.getIndex();
  357. const attributes = renderObject.getAttributes();
  358. gl.bindVertexArray( vaoGPU );
  359. if ( index !== null ) {
  360. const indexData = this.get( index );
  361. gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, indexData.bufferGPU );
  362. }
  363. for ( let i = 0; i < attributes.length; i ++ ) {
  364. const attribute = attributes[ i ];
  365. const attributeData = this.get( attribute );
  366. gl.bindBuffer( gl.ARRAY_BUFFER, attributeData.bufferGPU );
  367. gl.enableVertexAttribArray( i );
  368. let stride, offset;
  369. if ( attribute.isInterleavedBufferAttribute === true ) {
  370. stride = attribute.data.stride * attributeData.bytesPerElement;
  371. offset = attribute.offset * attributeData.bytesPerElement;
  372. } else {
  373. stride = 0;
  374. offset = 0;
  375. }
  376. if ( attributeData.isInteger ) {
  377. gl.vertexAttribIPointer( i, attribute.itemSize, attributeData.type, stride, offset );
  378. } else {
  379. gl.vertexAttribPointer( i, attribute.itemSize, attributeData.type, attribute.normalized, stride, offset );
  380. }
  381. if ( attribute.isInstancedBufferAttribute && ! attribute.isInterleavedBufferAttribute ) {
  382. gl.vertexAttribDivisor( i, attribute.meshPerAttribute );
  383. } else if ( attribute.isInterleavedBufferAttribute && attribute.data.isInstancedInterleavedBuffer ) {
  384. gl.vertexAttribDivisor( i, attribute.data.meshPerAttribute );
  385. }
  386. }
  387. gl.bindVertexArray( null );
  388. //
  389. this.set( pipeline, {
  390. programGPU,
  391. vaoGPU
  392. } );
  393. }
  394. createComputePipeline( /*computePipeline, bindings*/ ) {
  395. console.warn( 'Abstract class.' );
  396. }
  397. createBindings( bindings ) {
  398. this.updateBindings( bindings );
  399. }
  400. updateBindings( bindings ) {
  401. const { gl } = this;
  402. let groupIndex = 0;
  403. let textureIndex = 0;
  404. for ( const binding of bindings ) {
  405. if ( binding.isUniformsGroup || binding.isUniformBuffer ) {
  406. const bufferGPU = gl.createBuffer();
  407. const data = binding.buffer;
  408. gl.bindBuffer( gl.UNIFORM_BUFFER, bufferGPU );
  409. gl.bufferData( gl.UNIFORM_BUFFER, data, gl.DYNAMIC_DRAW );
  410. gl.bindBufferBase( gl.UNIFORM_BUFFER, groupIndex, bufferGPU );
  411. this.set( binding, {
  412. index: groupIndex ++,
  413. bufferGPU
  414. } );
  415. } else if ( binding.isSampledTexture ) {
  416. const { textureGPU, glTextureType } = this.get( binding.texture );
  417. this.set( binding, {
  418. index: textureIndex ++,
  419. textureGPU,
  420. glTextureType
  421. } );
  422. }
  423. }
  424. }
  425. updateBinding( binding ) {
  426. const gl = this.gl;
  427. if ( binding.isUniformsGroup || binding.isUniformBuffer ) {
  428. const bindingData = this.get( binding );
  429. const bufferGPU = bindingData.bufferGPU;
  430. const data = binding.buffer;
  431. gl.bindBuffer( gl.UNIFORM_BUFFER, bufferGPU );
  432. gl.bufferData( gl.UNIFORM_BUFFER, data, gl.DYNAMIC_DRAW );
  433. }
  434. }
  435. // attributes
  436. createIndexAttribute( attribute ) {
  437. const gl = this.gl;
  438. this.attributeUtils.createAttribute( attribute, gl.ELEMENT_ARRAY_BUFFER );
  439. }
  440. createAttribute( attribute ) {
  441. const gl = this.gl;
  442. this.attributeUtils.createAttribute( attribute, gl.ARRAY_BUFFER );
  443. }
  444. createStorageAttribute( /*attribute*/ ) {
  445. console.warn( 'Abstract class.' );
  446. }
  447. updateAttribute( attribute ) {
  448. this.attributeUtils.updateAttribute( attribute );
  449. }
  450. destroyAttribute( attribute ) {
  451. this.attributeUtils.destroyAttribute( attribute );
  452. }
  453. updateSize() {
  454. //console.warn( 'Abstract class.' );
  455. }
  456. hasFeature( name ) {
  457. const keysMatching = Object.keys( GLFeatureName ).filter( key => GLFeatureName[ key ] === name );
  458. const extensions = this.extensions;
  459. for ( let i = 0; i < keysMatching.length; i ++ ) {
  460. if ( extensions.has( keysMatching[ i ] ) ) return true;
  461. }
  462. return false;
  463. }
  464. getMaxAnisotropy() {
  465. return this.capabilities.getMaxAnisotropy();
  466. }
  467. copyFramebufferToTexture( texture, renderContext ) {
  468. this.textureUtils.copyFramebufferToTexture( texture, renderContext );
  469. }
  470. _setFramebuffer( renderContext ) {
  471. const { gl, state } = this;
  472. let currentFrameBuffer = null;
  473. if ( renderContext.textures !== null ) {
  474. const renderTarget = renderContext.renderTarget;
  475. const renderTargetContextData = this.get( renderTarget );
  476. const { samples, stencilBuffer } = renderTarget;
  477. const cubeFace = this.renderer._activeCubeFace;
  478. const isCube = renderTarget.isWebGLCubeRenderTarget === true;
  479. let msaaFb = renderTargetContextData.msaaFrameBuffer;
  480. let depthRenderbuffer = renderTargetContextData.depthRenderbuffer;
  481. let fb;
  482. if ( isCube ) {
  483. if ( renderTargetContextData.cubeFramebuffers === undefined ) {
  484. renderTargetContextData.cubeFramebuffers = [];
  485. }
  486. fb = renderTargetContextData.cubeFramebuffers[ cubeFace ];
  487. } else {
  488. fb = renderTargetContextData.framebuffer;
  489. }
  490. if ( fb === undefined ) {
  491. fb = gl.createFramebuffer();
  492. state.bindFramebuffer( gl.FRAMEBUFFER, fb );
  493. const textures = renderContext.textures;
  494. if ( isCube ) {
  495. renderTargetContextData.cubeFramebuffers[ cubeFace ] = fb;
  496. const { textureGPU } = this.get( textures[ 0 ] );
  497. gl.framebufferTexture2D( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + cubeFace, textureGPU, 0 );
  498. } else {
  499. for ( let i = 0; i < textures.length; i ++ ) {
  500. const texture = textures[ i ];
  501. const textureData = this.get( texture );
  502. textureData.renderTarget = renderContext.renderTarget;
  503. const attachment = gl.COLOR_ATTACHMENT0 + i;
  504. gl.framebufferTexture2D( gl.FRAMEBUFFER, attachment, gl.TEXTURE_2D, textureData.textureGPU, 0 );
  505. }
  506. renderTargetContextData.framebuffer = fb;
  507. state.drawBuffers( renderContext, fb );
  508. }
  509. if ( renderContext.depthTexture !== null ) {
  510. const textureData = this.get( renderContext.depthTexture );
  511. const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT;
  512. gl.framebufferTexture2D( gl.FRAMEBUFFER, depthStyle, gl.TEXTURE_2D, textureData.textureGPU, 0 );
  513. }
  514. }
  515. if ( samples > 0 ) {
  516. if ( msaaFb === undefined ) {
  517. const invalidationArray = [];
  518. msaaFb = gl.createFramebuffer();
  519. state.bindFramebuffer( gl.FRAMEBUFFER, msaaFb );
  520. // TODO For loop support MRT
  521. const msaaRenderbuffer = gl.createRenderbuffer();
  522. gl.bindRenderbuffer( gl.RENDERBUFFER, msaaRenderbuffer );
  523. const texture = renderContext.textures[ 0 ];
  524. const textureData = this.get( texture );
  525. gl.renderbufferStorageMultisample( gl.RENDERBUFFER, samples, textureData.glInternalFormat, renderContext.width, renderContext.height );
  526. gl.framebufferRenderbuffer( gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, msaaRenderbuffer );
  527. invalidationArray.push( gl.COLOR_ATTACHMENT0 );
  528. renderTargetContextData.msaaRenderbuffer = msaaRenderbuffer;
  529. renderTargetContextData.msaaFrameBuffer = msaaFb;
  530. if ( depthRenderbuffer === undefined ) {
  531. depthRenderbuffer = gl.createRenderbuffer();
  532. this.textureUtils.setupRenderBufferStorage( depthRenderbuffer, renderContext );
  533. renderTargetContextData.depthRenderbuffer = depthRenderbuffer;
  534. const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT;
  535. invalidationArray.push( depthStyle );
  536. }
  537. renderTargetContextData.invalidationArray = invalidationArray;
  538. }
  539. currentFrameBuffer = renderTargetContextData.msaaFrameBuffer;
  540. } else {
  541. currentFrameBuffer = fb;
  542. }
  543. }
  544. state.bindFramebuffer( gl.FRAMEBUFFER, currentFrameBuffer );
  545. }
  546. }
  547. export default WebGLBackend;