Browse Source

WebGPURenderer: Introduce `PostProcessingUtils` (#29595)

sunag 1 year ago
parent
commit
aedf298f33

+ 13 - 4
examples/jsm/tsl/display/AfterImageNode.js

@@ -1,10 +1,11 @@
-import { RenderTarget, Vector2 } from 'three';
+import { RenderTarget, Vector2, PostProcessingUtils } from 'three';
 import { TempNode, nodeObject, Fn, float, vec4, NodeUpdateType, uv, texture, passTexture, uniform, sign, max, convertToTexture, QuadMesh, NodeMaterial } from 'three/tsl';
 
 const _size = /*@__PURE__*/ new Vector2();
-
 const _quadMeshComp = /*@__PURE__*/ new QuadMesh();
 
+let _rendererState;
+
 class AfterImageNode extends TempNode {
 
 	static get type() {
@@ -50,6 +51,10 @@ class AfterImageNode extends TempNode {
 
 		const { renderer } = frame;
 
+		_rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState );
+
+		//
+
 		const textureNode = this.textureNode;
 		const map = textureNode.value;
 
@@ -62,23 +67,27 @@ class AfterImageNode extends TempNode {
 
 		this.setSize( _size.x, _size.y );
 
-		const currentRenderTarget = renderer.getRenderTarget();
 		const currentTexture = textureNode.value;
 
 		this.textureNodeOld.value = this._oldRT.texture;
 
 		// comp
+
 		renderer.setRenderTarget( this._compRT );
 		_quadMeshComp.render( renderer );
 
 		// Swap the textures
+
 		const temp = this._oldRT;
 		this._oldRT = this._compRT;
 		this._compRT = temp;
 
-		renderer.setRenderTarget( currentRenderTarget );
+		//
+
 		textureNode.value = currentTexture;
 
+		PostProcessingUtils.setRendererState( renderer, _rendererState );
+
 	}
 
 	setup( builder ) {

+ 9 - 3
examples/jsm/tsl/display/AnamorphicNode.js

@@ -1,8 +1,10 @@
-import { RenderTarget, Vector2 } from 'three';
+import { RenderTarget, Vector2, PostProcessingUtils } from 'three';
 import { TempNode, nodeObject, Fn, float, NodeUpdateType, uv, passTexture, uniform, convertToTexture, QuadMesh, NodeMaterial, vec2, vec3, Loop, threshold } from 'three/tsl';
 
 const _quadMesh = /*@__PURE__*/ new QuadMesh();
 
+let _rendererState;
+
 class AnamorphicNode extends TempNode {
 
 	static get type() {
@@ -54,12 +56,15 @@ class AnamorphicNode extends TempNode {
 
 		const { renderer } = frame;
 
+		_rendererState = PostProcessingUtils.getRendererState( renderer, _rendererState );
+
+		//
+
 		const textureNode = this.textureNode;
 		const map = textureNode.value;
 
 		this._renderTarget.texture.type = map.type;
 
-		const currentRenderTarget = renderer.getRenderTarget();
 		const currentTexture = textureNode.value;
 
 		_quadMesh.material = this._material;
@@ -74,9 +79,10 @@ class AnamorphicNode extends TempNode {
 
 		// restore
 
-		renderer.setRenderTarget( currentRenderTarget );
 		textureNode.value = currentTexture;
 
+		PostProcessingUtils.setRendererState( renderer, _rendererState );
+
 	}
 
 	setup( builder ) {

+ 7 - 16
examples/jsm/tsl/display/BloomNode.js

@@ -1,15 +1,14 @@
-import { Color, HalfFloatType, RenderTarget, Vector2, Vector3 } from 'three';
+import { HalfFloatType, RenderTarget, Vector2, Vector3, PostProcessingUtils } from 'three';
 import { TempNode, nodeObject, Fn, float, NodeUpdateType, uv, passTexture, uniform, QuadMesh, NodeMaterial, Loop, texture, luminance, smoothstep, mix, vec4, uniformArray, add, int } from 'three/tsl';
 
 const _quadMesh = /*@__PURE__*/ new QuadMesh();
-
-const _clearColor = /*@__PURE__*/ new Color( 0, 0, 0 );
-const _currentClearColor = /*@__PURE__*/ new Color();
 const _size = /*@__PURE__*/ new Vector2();
 
 const _BlurDirectionX = /*@__PURE__*/ new Vector2( 1.0, 0.0 );
 const _BlurDirectionY = /*@__PURE__*/ new Vector2( 0.0, 1.0 );
 
+let _rendererState;
+
 class BloomNode extends TempNode {
 
 	static get type() {
@@ -111,19 +110,13 @@ class BloomNode extends TempNode {
 
 		const { renderer } = frame;
 
-		const size = renderer.getDrawingBufferSize( _size );
-		this.setSize( size.width, size.height );
+		_rendererState = PostProcessingUtils.getRendererState( renderer, _rendererState );
 
-		const currentRenderTarget = renderer.getRenderTarget();
-		const currentMRT = renderer.getMRT();
-		renderer.getClearColor( _currentClearColor );
-		const currentClearAlpha = renderer.getClearAlpha();
+		//
 
+		const size = renderer.getDrawingBufferSize( _size );
 		this.setSize( size.width, size.height );
 
-		renderer.setMRT( null );
-		renderer.setClearColor( _clearColor, 0 );
-
 		// 1. Extract Bright Areas
 
 		renderer.setRenderTarget( this._renderTargetBright );
@@ -163,9 +156,7 @@ class BloomNode extends TempNode {
 
 		// restore
 
-		renderer.setRenderTarget( currentRenderTarget );
-		renderer.setMRT( currentMRT );
-		renderer.setClearColor( _currentClearColor, currentClearAlpha );
+		PostProcessingUtils.setRendererState( renderer, _rendererState );
 
 	}
 

+ 9 - 13
examples/jsm/tsl/display/GTAONode.js

@@ -1,10 +1,11 @@
-import { Color, DataTexture, RenderTarget, RepeatWrapping, Vector2, Vector3 } from 'three';
+import { DataTexture, RenderTarget, RepeatWrapping, Vector2, Vector3, PostProcessingUtils } from 'three';
 import { getViewPosition, QuadMesh, TempNode, nodeObject, Fn, float, NodeUpdateType, uv, uniform, Loop, vec2, vec3, vec4, int, dot, max, pow, abs, If, textureSize, sin, cos, PI, texture, passTexture, mat3, add, normalize, mul, cross, div, mix, sqrt, sub, acos, clamp, NodeMaterial } from 'three/tsl';
 
 const _quadMesh = /*@__PURE__*/ new QuadMesh();
-const _currentClearColor = /*@__PURE__*/ new Color();
 const _size = /*@__PURE__*/ new Vector2();
 
+let _rendererState;
+
 class GTAONode extends TempNode {
 
 	static get type() {
@@ -60,20 +61,17 @@ class GTAONode extends TempNode {
 
 		const { renderer } = frame;
 
-		const size = renderer.getDrawingBufferSize( _size );
-
-		const currentRenderTarget = renderer.getRenderTarget();
-		const currentMRT = renderer.getMRT();
-		renderer.getClearColor( _currentClearColor );
-		const currentClearAlpha = renderer.getClearAlpha();
+		_rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState );
 
-		_quadMesh.material = this._material;
+		//
 
+		const size = renderer.getDrawingBufferSize( _size );
 		this.setSize( size.width, size.height );
 
+		_quadMesh.material = this._material;
+
 		// clear
 
-		renderer.setMRT( null );
 		renderer.setClearColor( 0xffffff, 1 );
 
 		// ao
@@ -83,9 +81,7 @@ class GTAONode extends TempNode {
 
 		// restore
 
-		renderer.setRenderTarget( currentRenderTarget );
-		renderer.setMRT( currentMRT );
-		renderer.setClearColor( _currentClearColor, currentClearAlpha );
+		PostProcessingUtils.setRendererState( renderer, _rendererState );
 
 	}
 

+ 9 - 10
examples/jsm/tsl/display/GaussianBlurNode.js

@@ -1,4 +1,4 @@
-import { RenderTarget, Vector2 } from 'three';
+import { RenderTarget, Vector2, PostProcessingUtils } from 'three';
 import { TempNode, nodeObject, Fn, float, NodeUpdateType, uv, uniform, convertToTexture, vec2, vec4, QuadMesh, passTexture, mul, NodeMaterial } from 'three/tsl';
 
 // WebGPU: The use of a single QuadMesh for both gaussian blur passes results in a single RenderObject with a SampledTexture binding that
@@ -7,6 +7,8 @@ import { TempNode, nodeObject, Fn, float, NodeUpdateType, uv, uniform, convertTo
 const _quadMesh1 = /*@__PURE__*/ new QuadMesh();
 const _quadMesh2 = /*@__PURE__*/ new QuadMesh();
 
+let _rendererState;
+
 class GaussianBlurNode extends TempNode {
 
 	static get type() {
@@ -54,12 +56,13 @@ class GaussianBlurNode extends TempNode {
 
 		const { renderer } = frame;
 
+		_rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState );
+
+		//
+
 		const textureNode = this.textureNode;
 		const map = textureNode.value;
 
-		const currentRenderTarget = renderer.getRenderTarget();
-		const currentMRT = renderer.getMRT();
-
 		const currentTexture = textureNode.value;
 
 		_quadMesh1.material = this._material;
@@ -72,10 +75,6 @@ class GaussianBlurNode extends TempNode {
 		this._horizontalRT.texture.type = textureType;
 		this._verticalRT.texture.type = textureType;
 
-		// clear
-
-		renderer.setMRT( null );
-
 		// horizontal
 
 		renderer.setRenderTarget( this._horizontalRT );
@@ -95,10 +94,10 @@ class GaussianBlurNode extends TempNode {
 
 		// restore
 
-		renderer.setRenderTarget( currentRenderTarget );
-		renderer.setMRT( currentMRT );
 		textureNode.value = currentTexture;
 
+		PostProcessingUtils.setRendererState( renderer, _rendererState );
+
 	}
 
 	getTextureNode() {

+ 15 - 18
examples/jsm/tsl/display/OutlineNode.js

@@ -1,12 +1,13 @@
-import { Color, DepthTexture, FloatType, RenderTarget, Vector2 } from 'three';
+import { Color, DepthTexture, FloatType, RenderTarget, Vector2, PostProcessingUtils } from 'three';
 import { Loop, int, exp, min, float, mul, uv, vec2, vec3, Fn, textureSize, orthographicDepthToViewZ, QuadMesh, screenUV, TempNode, nodeObject, NodeUpdateType, uniform, vec4, NodeMaterial, passTexture, texture, perspectiveDepthToViewZ, positionView } from 'three/tsl';
 
 const _quadMesh = /*@__PURE__*/ new QuadMesh();
-const _currentClearColor = /*@__PURE__*/ new Color();
 const _size = /*@__PURE__*/ new Vector2();
 const _BLUR_DIRECTION_X = /*@__PURE__*/ new Vector2( 1.0, 0.0 );
 const _BLUR_DIRECTION_Y = /*@__PURE__*/ new Vector2( 0.0, 1.0 );
 
+let _rendererState;
+
 class OutlineNode extends TempNode {
 
 	static get type() {
@@ -151,28 +152,23 @@ class OutlineNode extends TempNode {
 		const { renderer } = frame;
 		const { camera, scene } = this;
 
+		_rendererState = PostProcessingUtils.resetRendererAndSceneState( renderer, scene, _rendererState );
+
+		//
+
 		const size = renderer.getDrawingBufferSize( _size );
 		this.setSize( size.width, size.height );
 
-		renderer.getClearColor( _currentClearColor );
-		const currentClearAlpha = renderer.getClearAlpha();
-		const currentRenderTarget = renderer.getRenderTarget();
-		const currentMRT = renderer.getMRT();
-		const currentBackground = scene.background;
-		const currentRenderObjectFunction = renderer.getRenderObjectFunction();
-
 		//
 
 		renderer.setClearColor( 0xffffff, 1 );
-		renderer.setMRT( null );
 
 		this._updateSelectionCache();
 
-		scene.background = null;
-
 		// 1. Draw non-selected objects in the depth buffer
 
 		scene.overrideMaterial = this._depthMaterial;
+
 		renderer.setRenderTarget( this._renderTargetDepthBuffer );
 		renderer.setRenderObjectFunction( ( object, ...params ) => {
 
@@ -183,11 +179,13 @@ class OutlineNode extends TempNode {
 			}
 
 		} );
+
 		renderer.render( scene, camera );
 
 		// 2. Draw only the selected objects by comparing the depth buffer of non-selected objects
 
 		scene.overrideMaterial = this._prepareMaskMaterial;
+
 		renderer.setRenderTarget( this._renderTargetMaskBuffer );
 		renderer.setRenderObjectFunction( ( object, ...params ) => {
 
@@ -198,11 +196,12 @@ class OutlineNode extends TempNode {
 			}
 
 		} );
+
 		renderer.render( scene, camera );
 
-		scene.overrideMaterial = null;
-		scene.background = currentBackground;
-		renderer.setRenderObjectFunction( currentRenderObjectFunction );
+		//
+
+		renderer.setRenderObjectFunction( _rendererState.renderObjectFunction );
 
 		this._selectionCache.clear();
 
@@ -256,9 +255,7 @@ class OutlineNode extends TempNode {
 
 		// restore
 
-		renderer.setRenderTarget( currentRenderTarget );
-		renderer.setMRT( currentMRT );
-		renderer.setClearColor( _currentClearColor, currentClearAlpha );
+		PostProcessingUtils.setRendererAndSceneState( renderer, scene, _rendererState );
 
 	}
 

+ 8 - 12
examples/jsm/tsl/display/SMAANode.js

@@ -1,10 +1,11 @@
-import { Color, HalfFloatType, LinearFilter, NearestFilter, RenderTarget, Texture, Vector2 } from 'three';
+import { HalfFloatType, LinearFilter, NearestFilter, RenderTarget, Texture, Vector2, PostProcessingUtils } from 'three';
 import { abs, QuadMesh, NodeMaterial, TempNode, nodeObject, Fn, NodeUpdateType, uv, uniform, convertToTexture, varyingProperty, vec2, vec4, modelViewProjection, passTexture, max, step, dot, float, texture, If, Loop, int, Break, sqrt, sign, mix } from 'three/tsl';
 
 const _quadMesh = /*@__PURE__*/ new QuadMesh();
-const _currentClearColor = /*@__PURE__*/ new Color();
 const _size = /*@__PURE__*/ new Vector2();
 
+let _rendererState;
+
 /**
  * Port of Subpixel Morphological Antialiasing (SMAA) v2.8
  * Preset: SMAA 1x Medium (with color edge detection)
@@ -120,15 +121,12 @@ class SMAANode extends TempNode {
 
 		const { renderer } = frame;
 
-		const size = renderer.getDrawingBufferSize( _size );
-		this.setSize( size.width, size.height );
+		_rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState );
 
-		const currentRenderTarget = renderer.getRenderTarget();
-		const currentMRT = renderer.getMRT();
-		renderer.getClearColor( _currentClearColor );
-		const currentClearAlpha = renderer.getClearAlpha();
+		//
 
-		renderer.setMRT( null );
+		const size = renderer.getDrawingBufferSize( _size );
+		this.setSize( size.width, size.height );
 
 		// edges
 
@@ -153,9 +151,7 @@ class SMAANode extends TempNode {
 
 		// restore
 
-		renderer.setRenderTarget( currentRenderTarget );
-		renderer.setMRT( currentMRT );
-		renderer.setClearColor( _currentClearColor, currentClearAlpha );
+		PostProcessingUtils.setRendererState( renderer, _rendererState );
 
 	}
 

+ 9 - 15
examples/jsm/tsl/display/SSAAPassNode.js

@@ -1,8 +1,10 @@
-import { AdditiveBlending, Color, Vector2 } from 'three';
+import { AdditiveBlending, Color, Vector2, PostProcessingUtils } from 'three';
 import { nodeObject, uniform, mrt, PassNode, QuadMesh, texture, NodeMaterial, getTextureIndex } from 'three/tsl';
 
 const _size = /*@__PURE__*/ new Vector2();
 
+let _rendererState;
+
 /**
 *
 * Supersample Anti-Aliasing Render Pass
@@ -32,8 +34,6 @@ class SSAAPassNode extends PassNode {
 		this.clearColor = new Color( 0x000000 );
 		this.clearAlpha = 0;
 
-		this._currentClearColor = new Color();
-
 		this.sampleWeight = uniform( 1 );
 
 		this.sampleRenderTarget = null;
@@ -47,6 +47,10 @@ class SSAAPassNode extends PassNode {
 		const { renderer } = frame;
 		const { scene, camera } = this;
 
+		_rendererState = PostProcessingUtils.getRendererAndSceneState( renderer, scene, _rendererState );
+
+		//
+
 		this._pixelRatio = renderer.getPixelRatio();
 
 		const size = renderer.getSize( _size );
@@ -54,14 +58,6 @@ class SSAAPassNode extends PassNode {
 		this.setSize( size.width, size.height );
 		this.sampleRenderTarget.setSize( this.renderTarget.width, this.renderTarget.height );
 
-		// save current renderer settings
-
-		renderer.getClearColor( this._currentClearColor );
-		const currentClearAlpha = renderer.getClearAlpha();
-		const currentRenderTarget = renderer.getRenderTarget();
-		const currentMRT = renderer.getMRT();
-		const currentAutoClear = renderer.autoClear;
-
 		//
 
 		this._cameraNear.value = camera.near;
@@ -165,11 +161,9 @@ class SSAAPassNode extends PassNode {
 
 		}
 
-		renderer.setRenderTarget( currentRenderTarget );
-		renderer.setMRT( currentMRT );
+		//
 
-		renderer.autoClear = currentAutoClear;
-		renderer.setClearColor( this._currentClearColor, currentClearAlpha );
+		PostProcessingUtils.setRendererAndSceneState( renderer, scene, _rendererState );
 
 	}
 

+ 8 - 4
examples/jsm/tsl/display/StereoCompositePassNode.js

@@ -1,9 +1,11 @@
-import { RenderTarget, StereoCamera, HalfFloatType, LinearFilter, NearestFilter, Vector2 } from 'three';
+import { RenderTarget, StereoCamera, HalfFloatType, LinearFilter, NearestFilter, Vector2, PostProcessingUtils } from 'three';
 import { PassNode, QuadMesh, texture } from 'three/tsl';
 
 const _size = /*@__PURE__*/ new Vector2();
 const _quadMesh = /*@__PURE__*/ new QuadMesh();
 
+let _rendererState;
+
 class StereoCompositePassNode extends PassNode {
 
 	static get type() {
@@ -53,6 +55,10 @@ class StereoCompositePassNode extends PassNode {
 		const { renderer } = frame;
 		const { scene, stereo, renderTarget } = this;
 
+		_rendererState = PostProcessingUtils.getRendererAndSceneState( renderer, scene, _rendererState );
+
+		//
+
 		this._pixelRatio = renderer.getPixelRatio();
 
 		this.updateStereoCamera( renderer.coordinateSystem );
@@ -60,8 +66,6 @@ class StereoCompositePassNode extends PassNode {
 		const size = renderer.getSize( _size );
 		this.setSize( size.width, size.height );
 
-		const currentRenderTarget = renderer.getRenderTarget();
-
 		// left
 
 		renderer.setRenderTarget( this._renderTargetL );
@@ -80,7 +84,7 @@ class StereoCompositePassNode extends PassNode {
 
 		// restore
 
-		renderer.setRenderTarget( currentRenderTarget );
+		PostProcessingUtils.setRendererState( renderer, scene, _rendererState );
 
 	}
 

+ 9 - 8
examples/jsm/tsl/display/StereoPassNode.js

@@ -1,8 +1,10 @@
-import { StereoCamera, Vector2 } from 'three';
+import { StereoCamera, Vector2, PostProcessingUtils } from 'three';
 import { PassNode, nodeObject } from 'three/tsl';
 
 const _size = /*@__PURE__*/ new Vector2();
 
+let _rendererState;
+
 class StereoPassNode extends PassNode {
 
 	static get type() {
@@ -27,6 +29,10 @@ class StereoPassNode extends PassNode {
 		const { renderer } = frame;
 		const { scene, camera, stereo, renderTarget } = this;
 
+		_rendererState = PostProcessingUtils.resetRendererState( renderer, _rendererState );
+
+		//
+
 		this._pixelRatio = renderer.getPixelRatio();
 
 		stereo.cameraL.coordinateSystem = renderer.coordinateSystem;
@@ -36,12 +42,8 @@ class StereoPassNode extends PassNode {
 		const size = renderer.getSize( _size );
 		this.setSize( size.width, size.height );
 
-		const currentAutoClear = renderer.autoClear;
 		renderer.autoClear = false;
 
-		const currentRenderTarget = renderer.getRenderTarget();
-		const currentMRT = renderer.getMRT();
-
 		this._cameraNear.value = camera.near;
 		this._cameraFar.value = camera.far;
 
@@ -67,10 +69,9 @@ class StereoPassNode extends PassNode {
 
 		renderTarget.scissorTest = false;
 
-		renderer.setRenderTarget( currentRenderTarget );
-		renderer.setMRT( currentMRT );
+		// restore
 
-		renderer.autoClear = currentAutoClear;
+		PostProcessingUtils.setRendererState( renderer, _rendererState );
 
 	}
 

+ 2 - 0
src/Three.WebGPU.Nodes.js

@@ -167,6 +167,8 @@ export { default as WebGPURenderer } from './renderers/webgpu/WebGPURenderer.Nod
 export { default as QuadMesh } from './renderers/common/QuadMesh.js';
 export { default as PMREMGenerator } from './renderers/common/extras/PMREMGenerator.js';
 export { default as PostProcessing } from './renderers/common/PostProcessing.js';
+import * as PostProcessingUtils from './renderers/common/PostProcessingUtils.js';
+export { PostProcessingUtils };
 export { default as StorageTexture } from './renderers/common/StorageTexture.js';
 export { default as StorageBufferAttribute } from './renderers/common/StorageBufferAttribute.js';
 export { default as StorageInstancedBufferAttribute } from './renderers/common/StorageInstancedBufferAttribute.js';

+ 2 - 0
src/Three.WebGPU.js

@@ -168,6 +168,8 @@ export { default as BundleGroup } from './renderers/common/BundleGroup.js';
 export { default as QuadMesh } from './renderers/common/QuadMesh.js';
 export { default as PMREMGenerator } from './renderers/common/extras/PMREMGenerator.js';
 export { default as PostProcessing } from './renderers/common/PostProcessing.js';
+import * as PostProcessingUtils from './renderers/common/PostProcessingUtils.js';
+export { PostProcessingUtils };
 export { default as StorageTexture } from './renderers/common/StorageTexture.js';
 export { default as StorageBufferAttribute } from './renderers/common/StorageBufferAttribute.js';
 export { default as StorageInstancedBufferAttribute } from './renderers/common/StorageInstancedBufferAttribute.js';

+ 86 - 0
src/renderers/common/PostProcessingUtils.js

@@ -0,0 +1,86 @@
+import { Color } from '../../math/Color.js';
+
+// renderer state
+
+export function getRendererState( renderer, state = {} ) {
+
+	state.toneMapping = renderer.toneMapping;
+	state.toneMappingExposure = renderer.toneMappingExposure;
+	state.outputColorSpace = renderer.outputColorSpace;
+	state.renderTarget = renderer.getRenderTarget();
+	state.activeCubeFace = renderer.getActiveCubeFace();
+	state.activeMipmapLevel = renderer.getActiveMipmapLevel();
+	state.renderObjectFunction = renderer.getRenderObjectFunction();
+	state.pixelRatio = renderer.getPixelRatio();
+	state.mrt = renderer.getMRT();
+	state.clearColor = renderer.getClearColor( state.clearColor || new Color() );
+	state.clearAlpha = renderer.getClearAlpha();
+	state.autoClear = renderer.autoClear;
+	state.scissorTest = renderer.getScissorTest();
+
+	return state;
+
+}
+
+export function resetRendererState( renderer, state ) {
+
+	state = getRendererState( renderer, state );
+
+	renderer.setMRT( null );
+	renderer.setRenderObjectFunction( null );
+	renderer.setClearColor( 0x000000, 1 );
+	renderer.autoClear = true;
+
+	return state;
+
+}
+
+export function setRendererState( renderer, state ) {
+
+	renderer.toneMapping = state.toneMapping;
+	renderer.toneMappingExposure = state.toneMappingExposure;
+	renderer.outputColorSpace = state.outputColorSpace;
+	renderer.setRenderTarget( state.renderTarget, state.activeCubeFace, state.activeMipmapLevel );
+	renderer.setRenderObjectFunction( state.renderObjectFunction );
+	renderer.setPixelRatio( state.pixelRatio );
+	renderer.setMRT( state.mrt );
+	renderer.setClearColor( state.clearColor, state.clearAlpha );
+	renderer.autoClear = state.autoClear;
+	renderer.setScissorTest( state.scissorTest );
+
+}
+
+// renderer and scene state
+
+export function getRendererAndSceneState( renderer, scene, state = {} ) {
+
+	state = getRendererState( renderer, state );
+	state.background = scene.background;
+	state.backgroundNode = scene.backgroundNode;
+	state.overrideMaterial = scene.overrideMaterial;
+
+	return state;
+
+}
+
+export function resetRendererAndSceneState( renderer, scene, state ) {
+
+	state = getRendererAndSceneState( renderer, scene, state );
+
+	scene.background = null;
+	scene.backgroundNode = null;
+	scene.overrideMaterial = null;
+
+	return state;
+
+}
+
+export function setRendererAndSceneState( renderer, scene, state ) {
+
+	setRendererState( renderer, state );
+
+	scene.background = state.background;
+	scene.backgroundNode = state.backgroundNode;
+	scene.overrideMaterial = state.overrideMaterial;
+
+}

+ 2 - 0
src/renderers/common/Renderer.js

@@ -825,6 +825,8 @@ class Renderer {
 
 	setPixelRatio( value = 1 ) {
 
+		if ( this._pixelRatio === value ) return;
+
 		this._pixelRatio = value;
 
 		this.setSize( this._width, this._height, false );

粤ICP备19079148号