three
Version:
JavaScript 3D library
226 lines (142 loc) • 5.27 kB
JavaScript
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, premultipliedAlpha ) {
const clearColor = new Color( 0x000000 );
let clearAlpha = 0;
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 };