import { BackSide, FrontSide, CubeUVReflectionMapping } from '../../constants.js'; import { BoxGeometry } from '../../geometries/BoxGeometry.js'; import { PlaneGeometry } from '../../geometries/PlaneGeometry.js'; import { ShaderMaterial } from '../../materials/ShaderMaterial.js'; import { Color } from '../../math/Color.js'; import { Mesh } from '../../objects/Mesh.js'; import { ShaderLib } from '../shaders/ShaderLib.js'; import { cloneUniforms } from '../shaders/UniformsUtils.js'; function WebGLBackground(renderer, cubemaps, state, objects, alpha, premultipliedAlpha) { const clearColor = new Color(0x000000); let clearAlpha = alpha === true ? 0 : 1; let planeMesh; let boxMesh; let currentBackground = null; let currentBackgroundVersion = 0; let currentTonemapping = null; function render(renderList, scene) { let forceClear = false; let background = scene.isScene === true ? scene.background : null; if (background && background.isTexture) { background = cubemaps.get(background); } // Ignore background in AR // TODO: Reconsider this. const xr = renderer.xr; const session = xr.getSession && xr.getSession(); if (session && session.environmentBlendMode === 'additive') { background = null; } if (background === null) { setClear(clearColor, clearAlpha); } else if (background && background.isColor) { setClear(background, 1); forceClear = true; } if (renderer.autoClear || forceClear) { renderer.clear(renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil); } if (background && (background.isCubeTexture || background.mapping === CubeUVReflectionMapping)) { if (boxMesh === undefined) { boxMesh = new Mesh( new BoxGeometry(1, 1, 1), new ShaderMaterial({ name: 'BackgroundCubeMaterial', uniforms: cloneUniforms(ShaderLib.cube.uniforms), vertexShader: ShaderLib.cube.vertexShader, fragmentShader: ShaderLib.cube.fragmentShader, side: BackSide, depthTest: false, depthWrite: false, fog: false, }) ); boxMesh.geometry.deleteAttribute('normal'); boxMesh.geometry.deleteAttribute('uv'); boxMesh.onBeforeRender = function (renderer, scene, camera) { this.matrixWorld.copyPosition(camera.matrixWorld); }; // enable code injection for non-built-in material Object.defineProperty(boxMesh.material, 'envMap', { get: function () { return this.uniforms.envMap.value; }, }); objects.update(boxMesh); } boxMesh.material.uniforms.envMap.value = background; boxMesh.material.uniforms.flipEnvMap.value = background.isCubeTexture && background.isRenderTargetTexture === false ? -1 : 1; if (currentBackground !== background || currentBackgroundVersion !== background.version || currentTonemapping !== renderer.toneMapping) { boxMesh.material.needsUpdate = true; currentBackground = background; currentBackgroundVersion = background.version; currentTonemapping = renderer.toneMapping; } // push to the pre-sorted opaque render list renderList.unshift(boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null); } else if (background && background.isTexture) { if (planeMesh === undefined) { planeMesh = new Mesh( new PlaneGeometry(2, 2), new ShaderMaterial({ name: 'BackgroundMaterial', uniforms: cloneUniforms(ShaderLib.background.uniforms), vertexShader: ShaderLib.background.vertexShader, fragmentShader: ShaderLib.background.fragmentShader, side: FrontSide, depthTest: false, depthWrite: false, fog: false, }) ); planeMesh.geometry.deleteAttribute('normal'); // enable code injection for non-built-in material Object.defineProperty(planeMesh.material, 'map', { get: function () { return this.uniforms.t2D.value; }, }); objects.update(planeMesh); } planeMesh.material.uniforms.t2D.value = background; if (background.matrixAutoUpdate === true) { background.updateMatrix(); } planeMesh.material.uniforms.uvTransform.value.copy(background.matrix); if (currentBackground !== background || currentBackgroundVersion !== background.version || currentTonemapping !== renderer.toneMapping) { planeMesh.material.needsUpdate = true; currentBackground = background; currentBackgroundVersion = background.version; currentTonemapping = renderer.toneMapping; } // push to the pre-sorted opaque render list renderList.unshift(planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null); } } function setClear(color, alpha) { state.buffers.color.setClear(color.r, color.g, color.b, alpha, premultipliedAlpha); } return { getClearColor: function () { return clearColor; }, setClearColor: function (color, alpha = 1) { clearColor.set(color); clearAlpha = alpha; setClear(clearColor, clearAlpha); }, getClearAlpha: function () { return clearAlpha; }, setClearAlpha: function (alpha) { clearAlpha = alpha; setClear(clearColor, clearAlpha); }, render: render, }; } export { WebGLBackground };