WebGLBackground.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import { BackSide, FrontSide, CubeUVReflectionMapping } from '../../constants.js';
  2. import { BoxBufferGeometry } from '../../geometries/BoxGeometry.js';
  3. import { PlaneBufferGeometry } from '../../geometries/PlaneGeometry.js';
  4. import { ShaderMaterial } from '../../materials/ShaderMaterial.js';
  5. import { Color } from '../../math/Color.js';
  6. import { Mesh } from '../../objects/Mesh.js';
  7. import { ShaderLib } from '../shaders/ShaderLib.js';
  8. import { cloneUniforms } from '../shaders/UniformsUtils.js';
  9. function WebGLBackground( renderer, cubemaps, state, objects, premultipliedAlpha ) {
  10. const clearColor = new Color( 0x000000 );
  11. let clearAlpha = 0;
  12. let planeMesh;
  13. let boxMesh;
  14. let currentBackground = null;
  15. let currentBackgroundVersion = 0;
  16. let currentTonemapping = null;
  17. function render( renderList, scene, camera, forceClear ) {
  18. let background = scene.isScene === true ? scene.background : null;
  19. if ( background && background.isTexture ) {
  20. background = cubemaps.get( background );
  21. }
  22. // Ignore background in AR
  23. // TODO: Reconsider this.
  24. const xr = renderer.xr;
  25. const session = xr.getSession && xr.getSession();
  26. if ( session && session.environmentBlendMode === 'additive' ) {
  27. background = null;
  28. }
  29. if ( background === null ) {
  30. setClear( clearColor, clearAlpha );
  31. } else if ( background && background.isColor ) {
  32. setClear( background, 1 );
  33. forceClear = true;
  34. }
  35. if ( renderer.autoClear || forceClear ) {
  36. renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
  37. }
  38. if ( background && ( background.isCubeTexture || background.isWebGLCubeRenderTarget || background.isWebGLCubeRenderTargetTexture || background.mapping === CubeUVReflectionMapping ) ) {
  39. if ( boxMesh === undefined ) {
  40. boxMesh = new Mesh(
  41. new BoxBufferGeometry( 1, 1, 1 ),
  42. new ShaderMaterial( {
  43. name: 'BackgroundCubeMaterial',
  44. uniforms: cloneUniforms( ShaderLib.cube.uniforms ),
  45. vertexShader: ShaderLib.cube.vertexShader,
  46. fragmentShader: ShaderLib.cube.fragmentShader,
  47. side: BackSide,
  48. depthTest: false,
  49. depthWrite: false,
  50. fog: false
  51. } )
  52. );
  53. boxMesh.geometry.deleteAttribute( 'normal' );
  54. boxMesh.geometry.deleteAttribute( 'uv' );
  55. boxMesh.onBeforeRender = function ( renderer, scene, camera ) {
  56. this.matrixWorld.copyPosition( camera.matrixWorld );
  57. };
  58. // enable code injection for non-built-in material
  59. Object.defineProperty( boxMesh.material, 'envMap', {
  60. get: function () {
  61. return this.uniforms.envMap.value;
  62. }
  63. } );
  64. objects.update( boxMesh );
  65. }
  66. if ( background.isWebGLCubeRenderTarget ) {
  67. // TODO Deprecate
  68. background = background.texture;
  69. }
  70. boxMesh.material.uniforms.envMap.value = background;
  71. boxMesh.material.uniforms.flipEnvMap.value = background.isCubeTexture ? - 1 : 1;
  72. if ( currentBackground !== background ||
  73. currentBackgroundVersion !== background.version ||
  74. currentTonemapping !== renderer.toneMapping ) {
  75. boxMesh.material.needsUpdate = true;
  76. currentBackground = background;
  77. currentBackgroundVersion = background.version;
  78. currentTonemapping = renderer.toneMapping;
  79. }
  80. // push to the pre-sorted opaque render list
  81. renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );
  82. } else if ( background && background.isTexture ) {
  83. if ( planeMesh === undefined ) {
  84. planeMesh = new Mesh(
  85. new PlaneBufferGeometry( 2, 2 ),
  86. new ShaderMaterial( {
  87. name: 'BackgroundMaterial',
  88. uniforms: cloneUniforms( ShaderLib.background.uniforms ),
  89. vertexShader: ShaderLib.background.vertexShader,
  90. fragmentShader: ShaderLib.background.fragmentShader,
  91. side: FrontSide,
  92. depthTest: false,
  93. depthWrite: false,
  94. fog: false
  95. } )
  96. );
  97. planeMesh.geometry.deleteAttribute( 'normal' );
  98. // enable code injection for non-built-in material
  99. Object.defineProperty( planeMesh.material, 'map', {
  100. get: function () {
  101. return this.uniforms.t2D.value;
  102. }
  103. } );
  104. objects.update( planeMesh );
  105. }
  106. planeMesh.material.uniforms.t2D.value = background;
  107. if ( background.matrixAutoUpdate === true ) {
  108. background.updateMatrix();
  109. }
  110. planeMesh.material.uniforms.uvTransform.value.copy( background.matrix );
  111. if ( currentBackground !== background ||
  112. currentBackgroundVersion !== background.version ||
  113. currentTonemapping !== renderer.toneMapping ) {
  114. planeMesh.material.needsUpdate = true;
  115. currentBackground = background;
  116. currentBackgroundVersion = background.version;
  117. currentTonemapping = renderer.toneMapping;
  118. }
  119. // push to the pre-sorted opaque render list
  120. renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );
  121. }
  122. }
  123. function setClear( color, alpha ) {
  124. state.buffers.color.setClear( color.r, color.g, color.b, alpha, premultipliedAlpha );
  125. }
  126. return {
  127. getClearColor: function () {
  128. return clearColor;
  129. },
  130. setClearColor: function ( color, alpha ) {
  131. clearColor.set( color );
  132. clearAlpha = alpha !== undefined ? alpha : 1;
  133. setClear( clearColor, clearAlpha );
  134. },
  135. getClearAlpha: function () {
  136. return clearAlpha;
  137. },
  138. setClearAlpha: function ( alpha ) {
  139. clearAlpha = alpha;
  140. setClear( clearColor, clearAlpha );
  141. },
  142. render: render
  143. };
  144. }
  145. export { WebGLBackground };