384 lines
9.9 KiB
JavaScript
384 lines
9.9 KiB
JavaScript
import { EventDispatcher } from './EventDispatcher.js';
|
|
import { Texture } from '../textures/Texture.js';
|
|
import { LinearFilter } from '../constants.js';
|
|
import { Vector4 } from '../math/Vector4.js';
|
|
import { Source } from '../textures/Source.js';
|
|
|
|
/**
|
|
* A render target is a buffer where the video card draws pixels for a scene
|
|
* that is being rendered in the background. It is used in different effects,
|
|
* such as applying postprocessing to a rendered image before displaying it
|
|
* on the screen.
|
|
*
|
|
* @augments EventDispatcher
|
|
*/
|
|
class RenderTarget extends EventDispatcher {
|
|
|
|
/**
|
|
* Render target options.
|
|
*
|
|
* @typedef {Object} RenderTarget~Options
|
|
* @property {boolean} [generateMipmaps=false] - Whether to generate mipmaps or not.
|
|
* @property {number} [magFilter=LinearFilter] - The mag filter.
|
|
* @property {number} [minFilter=LinearFilter] - The min filter.
|
|
* @property {number} [format=RGBAFormat] - The texture format.
|
|
* @property {number} [type=UnsignedByteType] - The texture type.
|
|
* @property {?string} [internalFormat=null] - The texture's internal format.
|
|
* @property {number} [wrapS=ClampToEdgeWrapping] - The texture's uv wrapping mode.
|
|
* @property {number} [wrapT=ClampToEdgeWrapping] - The texture's uv wrapping mode.
|
|
* @property {number} [anisotropy=1] - The texture's anisotropy value.
|
|
* @property {string} [colorSpace=NoColorSpace] - The texture's color space.
|
|
* @property {boolean} [depthBuffer=true] - Whether to allocate a depth buffer or not.
|
|
* @property {boolean} [stencilBuffer=false] - Whether to allocate a stencil buffer or not.
|
|
* @property {boolean} [resolveDepthBuffer=true] - Whether to resolve the depth buffer or not.
|
|
* @property {boolean} [resolveStencilBuffer=true] - Whether to resolve the stencil buffer or not.
|
|
* @property {?Texture} [depthTexture=null] - Reference to a depth texture.
|
|
* @property {number} [samples=0] - The MSAA samples count.
|
|
* @property {number} [count=1] - Defines the number of color attachments . Must be at least `1`.
|
|
* @property {number} [depth=1] - The texture depth.
|
|
* @property {boolean} [multiview=false] - Whether this target is used for multiview rendering.
|
|
*/
|
|
|
|
/**
|
|
* Constructs a new render target.
|
|
*
|
|
* @param {number} [width=1] - The width of the render target.
|
|
* @param {number} [height=1] - The height of the render target.
|
|
* @param {RenderTarget~Options} [options] - The configuration object.
|
|
*/
|
|
constructor( width = 1, height = 1, options = {} ) {
|
|
|
|
super();
|
|
|
|
options = Object.assign( {
|
|
generateMipmaps: false,
|
|
internalFormat: null,
|
|
minFilter: LinearFilter,
|
|
depthBuffer: true,
|
|
stencilBuffer: false,
|
|
resolveDepthBuffer: true,
|
|
resolveStencilBuffer: true,
|
|
depthTexture: null,
|
|
samples: 0,
|
|
count: 1,
|
|
depth: 1,
|
|
multiview: false
|
|
}, options );
|
|
|
|
/**
|
|
* This flag can be used for type testing.
|
|
*
|
|
* @type {boolean}
|
|
* @readonly
|
|
* @default true
|
|
*/
|
|
this.isRenderTarget = true;
|
|
|
|
/**
|
|
* The width of the render target.
|
|
*
|
|
* @type {number}
|
|
* @default 1
|
|
*/
|
|
this.width = width;
|
|
|
|
/**
|
|
* The height of the render target.
|
|
*
|
|
* @type {number}
|
|
* @default 1
|
|
*/
|
|
this.height = height;
|
|
|
|
/**
|
|
* The depth of the render target.
|
|
*
|
|
* @type {number}
|
|
* @default 1
|
|
*/
|
|
this.depth = options.depth;
|
|
|
|
/**
|
|
* A rectangular area inside the render target's viewport. Fragments that are
|
|
* outside the area will be discarded.
|
|
*
|
|
* @type {Vector4}
|
|
* @default (0,0,width,height)
|
|
*/
|
|
this.scissor = new Vector4( 0, 0, width, height );
|
|
|
|
/**
|
|
* Indicates whether the scissor test should be enabled when rendering into
|
|
* this render target or not.
|
|
*
|
|
* @type {boolean}
|
|
* @default false
|
|
*/
|
|
this.scissorTest = false;
|
|
|
|
/**
|
|
* A rectangular area representing the render target's viewport.
|
|
*
|
|
* @type {Vector4}
|
|
* @default (0,0,width,height)
|
|
*/
|
|
this.viewport = new Vector4( 0, 0, width, height );
|
|
|
|
const image = { width: width, height: height, depth: options.depth };
|
|
|
|
const texture = new Texture( image );
|
|
|
|
/**
|
|
* An array of textures. Each color attachment is represented as a separate texture.
|
|
* Has at least a single entry for the default color attachment.
|
|
*
|
|
* @type {Array<Texture>}
|
|
*/
|
|
this.textures = [];
|
|
|
|
const count = options.count;
|
|
for ( let i = 0; i < count; i ++ ) {
|
|
|
|
this.textures[ i ] = texture.clone();
|
|
this.textures[ i ].isRenderTargetTexture = true;
|
|
this.textures[ i ].renderTarget = this;
|
|
|
|
}
|
|
|
|
this._setTextureOptions( options );
|
|
|
|
/**
|
|
* Whether to allocate a depth buffer or not.
|
|
*
|
|
* @type {boolean}
|
|
* @default true
|
|
*/
|
|
this.depthBuffer = options.depthBuffer;
|
|
|
|
/**
|
|
* Whether to allocate a stencil buffer or not.
|
|
*
|
|
* @type {boolean}
|
|
* @default false
|
|
*/
|
|
this.stencilBuffer = options.stencilBuffer;
|
|
|
|
/**
|
|
* Whether to resolve the depth buffer or not.
|
|
*
|
|
* @type {boolean}
|
|
* @default true
|
|
*/
|
|
this.resolveDepthBuffer = options.resolveDepthBuffer;
|
|
|
|
/**
|
|
* Whether to resolve the stencil buffer or not.
|
|
*
|
|
* @type {boolean}
|
|
* @default true
|
|
*/
|
|
this.resolveStencilBuffer = options.resolveStencilBuffer;
|
|
|
|
this._depthTexture = null;
|
|
this.depthTexture = options.depthTexture;
|
|
|
|
/**
|
|
* The number of MSAA samples.
|
|
*
|
|
* A value of `0` disables MSAA.
|
|
*
|
|
* @type {number}
|
|
* @default 0
|
|
*/
|
|
this.samples = options.samples;
|
|
|
|
/**
|
|
* Whether to this target is used in multiview rendering.
|
|
*
|
|
* @type {boolean}
|
|
* @default false
|
|
*/
|
|
this.multiview = options.multiview;
|
|
|
|
}
|
|
|
|
_setTextureOptions( options = {} ) {
|
|
|
|
const values = {
|
|
minFilter: LinearFilter,
|
|
generateMipmaps: false,
|
|
flipY: false,
|
|
internalFormat: null
|
|
};
|
|
|
|
if ( options.mapping !== undefined ) values.mapping = options.mapping;
|
|
if ( options.wrapS !== undefined ) values.wrapS = options.wrapS;
|
|
if ( options.wrapT !== undefined ) values.wrapT = options.wrapT;
|
|
if ( options.wrapR !== undefined ) values.wrapR = options.wrapR;
|
|
if ( options.magFilter !== undefined ) values.magFilter = options.magFilter;
|
|
if ( options.minFilter !== undefined ) values.minFilter = options.minFilter;
|
|
if ( options.format !== undefined ) values.format = options.format;
|
|
if ( options.type !== undefined ) values.type = options.type;
|
|
if ( options.anisotropy !== undefined ) values.anisotropy = options.anisotropy;
|
|
if ( options.colorSpace !== undefined ) values.colorSpace = options.colorSpace;
|
|
if ( options.flipY !== undefined ) values.flipY = options.flipY;
|
|
if ( options.generateMipmaps !== undefined ) values.generateMipmaps = options.generateMipmaps;
|
|
if ( options.internalFormat !== undefined ) values.internalFormat = options.internalFormat;
|
|
|
|
for ( let i = 0; i < this.textures.length; i ++ ) {
|
|
|
|
const texture = this.textures[ i ];
|
|
texture.setValues( values );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* The texture representing the default color attachment.
|
|
*
|
|
* @type {Texture}
|
|
*/
|
|
get texture() {
|
|
|
|
return this.textures[ 0 ];
|
|
|
|
}
|
|
|
|
set texture( value ) {
|
|
|
|
this.textures[ 0 ] = value;
|
|
|
|
}
|
|
|
|
set depthTexture( current ) {
|
|
|
|
if ( this._depthTexture !== null ) this._depthTexture.renderTarget = null;
|
|
if ( current !== null ) current.renderTarget = this;
|
|
|
|
this._depthTexture = current;
|
|
|
|
}
|
|
|
|
/**
|
|
* Instead of saving the depth in a renderbuffer, a texture
|
|
* can be used instead which is useful for further processing
|
|
* e.g. in context of post-processing.
|
|
*
|
|
* @type {?DepthTexture}
|
|
* @default null
|
|
*/
|
|
get depthTexture() {
|
|
|
|
return this._depthTexture;
|
|
|
|
}
|
|
|
|
/**
|
|
* Sets the size of this render target.
|
|
*
|
|
* @param {number} width - The width.
|
|
* @param {number} height - The height.
|
|
* @param {number} [depth=1] - The depth.
|
|
*/
|
|
setSize( width, height, depth = 1 ) {
|
|
|
|
if ( this.width !== width || this.height !== height || this.depth !== depth ) {
|
|
|
|
this.width = width;
|
|
this.height = height;
|
|
this.depth = depth;
|
|
|
|
for ( let i = 0, il = this.textures.length; i < il; i ++ ) {
|
|
|
|
this.textures[ i ].image.width = width;
|
|
this.textures[ i ].image.height = height;
|
|
this.textures[ i ].image.depth = depth;
|
|
this.textures[ i ].isArrayTexture = this.textures[ i ].image.depth > 1;
|
|
|
|
}
|
|
|
|
this.dispose();
|
|
|
|
}
|
|
|
|
this.viewport.set( 0, 0, width, height );
|
|
this.scissor.set( 0, 0, width, height );
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns a new render target with copied values from this instance.
|
|
*
|
|
* @return {RenderTarget} A clone of this instance.
|
|
*/
|
|
clone() {
|
|
|
|
return new this.constructor().copy( this );
|
|
|
|
}
|
|
|
|
/**
|
|
* Copies the settings of the given render target. This is a structural copy so
|
|
* no resources are shared between render targets after the copy. That includes
|
|
* all MRT textures and the depth texture.
|
|
*
|
|
* @param {RenderTarget} source - The render target to copy.
|
|
* @return {RenderTarget} A reference to this instance.
|
|
*/
|
|
copy( source ) {
|
|
|
|
this.width = source.width;
|
|
this.height = source.height;
|
|
this.depth = source.depth;
|
|
|
|
this.scissor.copy( source.scissor );
|
|
this.scissorTest = source.scissorTest;
|
|
|
|
this.viewport.copy( source.viewport );
|
|
|
|
this.textures.length = 0;
|
|
|
|
for ( let i = 0, il = source.textures.length; i < il; i ++ ) {
|
|
|
|
this.textures[ i ] = source.textures[ i ].clone();
|
|
this.textures[ i ].isRenderTargetTexture = true;
|
|
this.textures[ i ].renderTarget = this;
|
|
|
|
// ensure image object is not shared, see #20328
|
|
|
|
const image = Object.assign( {}, source.textures[ i ].image );
|
|
this.textures[ i ].source = new Source( image );
|
|
|
|
}
|
|
|
|
this.depthBuffer = source.depthBuffer;
|
|
this.stencilBuffer = source.stencilBuffer;
|
|
|
|
this.resolveDepthBuffer = source.resolveDepthBuffer;
|
|
this.resolveStencilBuffer = source.resolveStencilBuffer;
|
|
|
|
if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone();
|
|
|
|
this.samples = source.samples;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
/**
|
|
* Frees the GPU-related resources allocated by this instance. Call this
|
|
* method whenever this instance is no longer used in your app.
|
|
*
|
|
* @fires RenderTarget#dispose
|
|
*/
|
|
dispose() {
|
|
|
|
this.dispatchEvent( { type: 'dispose' } );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export { RenderTarget };
|