diff --git a/examples/webgpu_lights_custom.html b/examples/webgpu_lights_custom.html
index afbe5b5dfe5fc1..398695edc4e75a 100644
--- a/examples/webgpu_lights_custom.html
+++ b/examples/webgpu_lights_custom.html
@@ -113,6 +113,7 @@
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animate );
+ renderer.toneMapping = THREE.LinearToneMapping;
document.body.appendChild( renderer.domElement );
// controls
diff --git a/src/renderers/common/Backend.js b/src/renderers/common/Backend.js
index 028b74463d26eb..8b42632d2997a0 100644
--- a/src/renderers/common/Backend.js
+++ b/src/renderers/common/Backend.js
@@ -4,7 +4,7 @@ let _color4 = null;
import Color4 from './Color4.js';
import { Vector2 } from '../../math/Vector2.js';
import { createCanvasElement, warnOnce } from '../../utils.js';
-import { REVISION } from '../../constants.js';
+import { HalfFloatType, REVISION } from '../../constants.js';
/**
* Most of the rendering related logic is implemented in the
@@ -588,6 +588,17 @@ class Backend {
}
+ /**
+ * Returns `true` if the backend requires a framebuffer target with type `HalfFloat`.
+ *
+ * @return {Boolean} Whether the backend requires a framebuffer target with type `HalfFloat` or not.
+ */
+ needsHalfFloatFrameBufferTarget() {
+
+ return ( this.parameters.outputType === HalfFloatType );
+
+ }
+
/**
* Sets a dictionary for the given object into the
* internal data structure.
diff --git a/src/renderers/common/Renderer.js b/src/renderers/common/Renderer.js
index 6463696ff0c625..b8a36ef1ea8fbc 100644
--- a/src/renderers/common/Renderer.js
+++ b/src/renderers/common/Renderer.js
@@ -26,7 +26,7 @@ import { Matrix4 } from '../../math/Matrix4.js';
import { Vector2 } from '../../math/Vector2.js';
import { Vector4 } from '../../math/Vector4.js';
import { RenderTarget } from '../../core/RenderTarget.js';
-import { DoubleSide, BackSide, FrontSide, SRGBColorSpace, NoToneMapping, LinearFilter, LinearSRGBColorSpace, HalfFloatType, RGBAFormat, PCFShadowMap } from '../../constants.js';
+import { DoubleSide, BackSide, FrontSide, SRGBColorSpace, NoToneMapping, LinearFilter, LinearSRGBColorSpace, HalfFloatType, RGBAFormat, PCFShadowMap, UnsignedByteType } from '../../constants.js';
/** @module Renderer **/
@@ -445,13 +445,13 @@ class Renderer {
this._transparentSort = null;
/**
- * The framebuffer target.
+ * A map that holds a framebuffer target for each render
+ * target type.
*
* @private
- * @type {RenderTarget?}
- * @default null
+ * @type {Map}
*/
- this._frameBufferTarget = null;
+ this._frameBufferTargetMap = new Map();
const alphaClear = this.alpha === true ? 0 : 1;
@@ -1121,14 +1121,19 @@ class Renderer {
const { width, height } = this.getDrawingBufferSize( _drawingBufferSize );
const { depth, stencil } = this;
- let frameBufferTarget = this._frameBufferTarget;
+ // to improve performance we only want to use HalfFloatType if necessary
+ // HalfFloatType is required when a) tone mapping is used or b) the backend specifically requests it
+
+ const type = ( useToneMapping || this.backend.needsHalfFloatFrameBufferTarget() ) ? HalfFloatType : UnsignedByteType;
- if ( frameBufferTarget === null ) {
+ let frameBufferTarget = this._frameBufferTargetMap.get( type );
+
+ if ( frameBufferTarget === undefined ) {
frameBufferTarget = new RenderTarget( width, height, {
depthBuffer: depth,
stencilBuffer: stencil,
- type: HalfFloatType, // FloatType
+ type: type,
format: RGBAFormat,
colorSpace: LinearSRGBColorSpace,
generateMipmaps: false,
@@ -1139,7 +1144,7 @@ class Renderer {
frameBufferTarget.isPostProcessingRenderTarget = true;
- this._frameBufferTarget = frameBufferTarget;
+ this._frameBufferTargetMap.set( type, frameBufferTarget );
}
@@ -2026,6 +2031,14 @@ class Renderer {
this._renderContexts.dispose();
this._textures.dispose();
+ for ( const renderTarget of this._frameBufferTargetMap.values() ) {
+
+ renderTarget.dispose();
+
+ }
+
+ this._frameBufferTargetMap.clear();
+
Object.values( this.backend.timestampQueryPool ).forEach( queryPool => {
if ( queryPool !== null ) queryPool.dispose();