2
0
Эх сурвалжийг харах

WebGPURenderer: CubeRenderTarget and CubeCamera (#26152)

* Core: Introduce Coordinate System.

* WebGPURenderer: Move hack to .coordinateSystem

* cleanup

* ToneMappingNode: Fix caching

* Renderer Nodes: cleanup

* CubeCamera: Introduce Coordinate System

* NodeMaterial: Fixing currently colorSpace and environment

* WebGPURenderer: Added CubeRenderTarget support

* Examples: Added webgpu_cubemap_dynamic

* CubeCamera: Fix .lookAt() if the object changes position.

* CubeCamera: Set WebGLCoordinateSystem as default

* Added totalScattering

* Added envMapIntensity

* Added CubeRenderTarget.fromEquirectangularTexture()

* Update webgpu_loader_gltf.html

* cleanup

* update screenshots

* revisions

* cleanup

* cleanup

* update example description
sunag 2 жил өмнө
parent
commit
517ce63ecc

+ 1 - 0
examples/files.json

@@ -309,6 +309,7 @@
 		"webgpu_backdrop",
 		"webgpu_backdrop",
 		"webgpu_compute",
 		"webgpu_compute",
 		"webgpu_cubemap_adjustments",
 		"webgpu_cubemap_adjustments",
+		"webgpu_cubemap_dynamic",
 		"webgpu_cubemap_mix",
 		"webgpu_cubemap_mix",
 		"webgpu_depth_texture",
 		"webgpu_depth_texture",
 		"webgpu_equirectangular",
 		"webgpu_equirectangular",

+ 9 - 0
examples/jsm/nodes/display/ToneMappingNode.js

@@ -95,6 +95,15 @@ class ToneMappingNode extends TempNode {
 
 
 	}
 	}
 
 
+	getCacheKey() {
+
+		let cacheKey = super.getCacheKey();
+		cacheKey = '{toneMapping:' + this.toneMapping + ',nodes:' + cacheKey + '}';
+
+		return cacheKey;
+
+	}
+
 	construct( builder ) {
 	construct( builder ) {
 
 
 		const colorNode = this.colorNode || builder.context.color;
 		const colorNode = this.colorNode || builder.context.color;

+ 3 - 1
examples/jsm/nodes/functions/PhysicalLightingModel.js

@@ -40,7 +40,9 @@ const RE_IndirectSpecular_Physical = new ShaderNode( ( inputs ) => {
 
 
 	computeMultiscattering( singleScattering, multiScattering );
 	computeMultiscattering( singleScattering, multiScattering );
 
 
-	const diffuse = diffuseColor.mul( singleScattering.add( multiScattering ).oneMinus() );
+	const totalScattering = singleScattering.add( multiScattering );
+
+	const diffuse = diffuseColor.mul( totalScattering.r.max( totalScattering.g ).max( totalScattering.b ).oneMinus() );
 
 
 	reflectedLight.indirectSpecular.addAssign( radiance.mul( singleScattering ) );
 	reflectedLight.indirectSpecular.addAssign( radiance.mul( singleScattering ) );
 	reflectedLight.indirectSpecular.addAssign( multiScattering.mul( cosineWeightedIrradiance ) );
 	reflectedLight.indirectSpecular.addAssign( multiScattering.mul( cosineWeightedIrradiance ) );

+ 19 - 3
examples/jsm/nodes/lighting/EnvironmentNode.js

@@ -9,6 +9,8 @@ import { transformedNormalView, transformedNormalWorld } from '../accessors/Norm
 import { positionViewDirection } from '../accessors/PositionNode.js';
 import { positionViewDirection } from '../accessors/PositionNode.js';
 import { addNodeClass } from '../core/Node.js';
 import { addNodeClass } from '../core/Node.js';
 import { float, vec2 } from '../shadernode/ShaderNode.js';
 import { float, vec2 } from '../shadernode/ShaderNode.js';
+import { cubeTexture } from '../accessors/CubeTextureNode.js';
+import { reference } from '../accessors/ReferenceNode.js';
 
 
 class EnvironmentNode extends LightingNode {
 class EnvironmentNode extends LightingNode {
 
 
@@ -22,9 +24,21 @@ class EnvironmentNode extends LightingNode {
 
 
 	construct( builder ) {
 	construct( builder ) {
 
 
-		const envNode = this.envNode;
+		let envNode = this.envNode;
 		const properties = builder.getNodeProperties( this );
 		const properties = builder.getNodeProperties( this );
 
 
+		if ( envNode.isTextureNode && envNode.value.isCubeTexture !== true ) {
+
+			const texture = envNode.value;
+			const renderer = builder.renderer;
+
+			// @TODO: Add dispose logic here
+			const cubeRTT = builder.getCubeRenderTarget( 512 ).fromEquirectangularTexture( renderer, texture );
+
+			envNode = cubeTexture( cubeRTT.texture );
+
+		}
+
 		let reflectVec;
 		let reflectVec;
 		let radianceTextureUVNode;
 		let radianceTextureUVNode;
 		let irradianceTextureUVNode;
 		let irradianceTextureUVNode;
@@ -120,9 +134,11 @@ class EnvironmentNode extends LightingNode {
 
 
 		//
 		//
 
 
-		builder.context.radiance.addAssign( isolateRadianceFlowContext );
+		const intensity = reference( 'envMapIntensity', 'float', builder.material );
+
+		builder.context.radiance.addAssign( isolateRadianceFlowContext.mul( intensity ) );
 
 
-		builder.context.iblIrradiance.addAssign( irradianceContext.mul( Math.PI ) );
+		builder.context.iblIrradiance.addAssign( irradianceContext.mul( Math.PI ).mul( intensity ) );
 
 
 		properties.radianceContext = isolateRadianceFlowContext;
 		properties.radianceContext = isolateRadianceFlowContext;
 		properties.irradianceContext = irradianceContext;
 		properties.irradianceContext = irradianceContext;

+ 42 - 3
examples/jsm/nodes/materials/NodeMaterial.js

@@ -1,4 +1,4 @@
-import { Material, ShaderMaterial } from 'three';
+import { Material, ShaderMaterial, NoColorSpace } from 'three';
 import { getNodeChildren, getCacheKey } from '../core/NodeUtils.js';
 import { getNodeChildren, getCacheKey } from '../core/NodeUtils.js';
 import { attribute } from '../core/AttributeNode.js';
 import { attribute } from '../core/AttributeNode.js';
 import { diffuseColor } from '../core/PropertyNode.js';
 import { diffuseColor } from '../core/PropertyNode.js';
@@ -10,6 +10,7 @@ import { instance } from '../accessors/InstanceNode.js';
 import { positionLocal } from '../accessors/PositionNode.js';
 import { positionLocal } from '../accessors/PositionNode.js';
 import { skinning } from '../accessors/SkinningNode.js';
 import { skinning } from '../accessors/SkinningNode.js';
 import { texture } from '../accessors/TextureNode.js';
 import { texture } from '../accessors/TextureNode.js';
+import { cubeTexture } from '../accessors/CubeTextureNode.js';
 import { lightsWithoutWrap } from '../lighting/LightsNode.js';
 import { lightsWithoutWrap } from '../lighting/LightsNode.js';
 import { mix } from '../math/MathNode.js';
 import { mix } from '../math/MathNode.js';
 import { float, vec3, vec4 } from '../shadernode/ShaderNode.js';
 import { float, vec3, vec4 } from '../shadernode/ShaderNode.js';
@@ -165,9 +166,33 @@ class NodeMaterial extends ShaderMaterial {
 
 
 	}
 	}
 
 
+	getEnvNode( builder ) {
+
+		let node = null;
+
+		if ( this.envNode ) {
+
+			node = this.envNode;
+
+		} else if ( this.envMap ) {
+
+			node = this.envMap.isCubeTexture ? cubeTexture( this.envMap ) : texture( this.envMap );
+
+		} else if ( builder.environmentNode ) {
+
+			node = builder.environmentNode;
+
+		}
+
+		return node;
+
+	}
+
 	constructLights( builder ) {
 	constructLights( builder ) {
 
 
-		const envNode = this.envNode || builder.environmentNode;
+		const envNode = this.getEnvNode( builder );
+
+		//
 
 
 		const materialLightsNode = [];
 		const materialLightsNode = [];
 
 
@@ -257,7 +282,21 @@ class NodeMaterial extends ShaderMaterial {
 
 
 		// ENCODING
 		// ENCODING
 
 
-		outputNode = outputNode.colorSpace( renderer.outputColorSpace );
+		const renderTarget = renderer.getRenderTarget();
+
+		let outputColorSpace;
+
+		if ( renderTarget !== null ) {
+
+			outputColorSpace = renderTarget.texture.colorSpace;
+
+		} else {
+
+			outputColorSpace = renderer.outputColorSpace;
+
+		}
+
+		if ( outputColorSpace !== NoColorSpace ) outputNode = outputNode.colorSpace( outputColorSpace );
 
 
 		// FOG
 		// FOG
 
 

+ 65 - 0
examples/jsm/renderers/common/CubeRenderTarget.js

@@ -0,0 +1,65 @@
+import { WebGLCubeRenderTarget, Scene, CubeCamera, BoxGeometry, Mesh, BackSide, NoBlending, LinearFilter, LinearMipmapLinearFilter } from 'three';
+import { equirectUV } from '../../nodes/utils/EquirectUVNode.js';
+import { texture as TSL_Texture } from '../../nodes/accessors/TextureNode.js';
+import { positionWorldDirection } from '../../nodes/accessors/PositionNode.js';
+import { createNodeMaterialFromType } from '../../nodes/materials/NodeMaterial.js';
+
+// @TODO: Consider rename WebGLCubeRenderTarget to just CubeRenderTarget
+
+class CubeRenderTarget extends WebGLCubeRenderTarget {
+
+	constructor( size = 1, options = {} ) {
+
+		super( size, options );
+
+		this.isCubeRenderTarget = true;
+
+	}
+
+	fromEquirectangularTexture( renderer, texture ) {
+
+		const currentMinFilter = texture.minFilter;
+		const currentGenerateMipmaps = texture.generateMipmaps;
+
+		texture.generateMipmaps = true;
+
+		this.texture.type = texture.type;
+		this.texture.colorSpace = texture.colorSpace;
+
+		this.texture.generateMipmaps = texture.generateMipmaps;
+		this.texture.minFilter = texture.minFilter;
+		this.texture.magFilter = texture.magFilter;
+
+		const geometry = new BoxGeometry( 5, 5, 5 );
+
+		const uvNode = equirectUV( positionWorldDirection );
+
+		const material = createNodeMaterialFromType( 'MeshBasicNodeMaterial' );
+		material.colorNode = TSL_Texture( texture, uvNode, 0 );
+		material.side = BackSide;
+		material.blending = NoBlending;
+
+		const mesh = new Mesh( geometry, material );
+
+		const scene = new Scene();
+		scene.add( mesh );
+
+		// Avoid blurred poles
+		if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter;
+
+		const camera = new CubeCamera( 1, 10, this );
+		camera.update( renderer, scene );
+
+		texture.minFilter = currentMinFilter;
+		texture.currentGenerateMipmaps = currentGenerateMipmaps;
+
+		mesh.geometry.dispose();
+		mesh.material.dispose();
+
+		return this;
+
+	}
+
+}
+
+export default CubeRenderTarget;

+ 1 - 0
examples/jsm/renderers/common/RenderContext.js

@@ -28,6 +28,7 @@ class RenderContext {
 
 
 		this.texture = null;
 		this.texture = null;
 		this.depthTexture = null;
 		this.depthTexture = null;
+		this.activeCubeFace = 0;
 
 
 	}
 	}
 
 

+ 11 - 2
examples/jsm/renderers/common/Renderer.js

@@ -79,6 +79,7 @@ class Renderer {
 		this._clearStencil = 0;
 		this._clearStencil = 0;
 
 
 		this._renderTarget = null;
 		this._renderTarget = null;
+		this._currentActiveCubeFace = 0;
 
 
 		this._initialized = false;
 		this._initialized = false;
 		this._initPromise = null;
 		this._initPromise = null;
@@ -90,6 +91,10 @@ class Renderer {
 			type: null
 			type: null
 		};
 		};
 
 
+		this.xr = {
+			enabled: false
+		};
+
 	}
 	}
 
 
 	async init() {
 	async init() {
@@ -154,7 +159,7 @@ class Renderer {
 
 
 	}
 	}
 
 
-	async compile( scene, camera ) {
+	async compile( /*scene, camera*/ ) {
 
 
 		console.warn( 'THREE.Renderer: .compile() is not implemented yet.' );
 		console.warn( 'THREE.Renderer: .compile() is not implemented yet.' );
 
 
@@ -175,6 +180,7 @@ class Renderer {
 
 
 		const renderContext = this._renderContexts.get( scene, camera );
 		const renderContext = this._renderContexts.get( scene, camera );
 		const renderTarget = this._renderTarget;
 		const renderTarget = this._renderTarget;
+		const activeCubeFace = this._activeCubeFace;
 
 
 		this._currentRenderContext = renderContext;
 		this._currentRenderContext = renderContext;
 
 
@@ -269,6 +275,8 @@ class Renderer {
 
 
 		}
 		}
 
 
+		renderContext.activeCubeFace = activeCubeFace;
+
 		//
 		//
 
 
 		this._nodes.updateScene( scene );
 		this._nodes.updateScene( scene );
@@ -560,9 +568,10 @@ class Renderer {
 
 
 	}
 	}
 
 
-	setRenderTarget( renderTarget ) {
+	setRenderTarget( renderTarget, activeCubeFace = 0 ) {
 
 
 		this._renderTarget = renderTarget;
 		this._renderTarget = renderTarget;
+		this._activeCubeFace = activeCubeFace;
 
 
 	}
 	}
 
 

+ 1 - 1
examples/jsm/renderers/common/SampledTexture.js

@@ -11,7 +11,7 @@ class SampledTexture extends Binding {
 		this.id = id ++;
 		this.id = id ++;
 
 
 		this.texture = texture;
 		this.texture = texture;
-		this.version = 0;
+		this.version = texture.version;
 
 
 		this.isSampledTexture = true;
 		this.isSampledTexture = true;
 
 

+ 1 - 1
examples/jsm/renderers/common/Sampler.js

@@ -7,7 +7,7 @@ class Sampler extends Binding {
 		super( name );
 		super( name );
 
 
 		this.texture = texture;
 		this.texture = texture;
-		this.version = 0;
+		this.version = texture.version;
 
 
 		this.isSampler = true;
 		this.isSampler = true;
 
 

+ 29 - 8
examples/jsm/renderers/common/Textures.js

@@ -1,5 +1,7 @@
 import DataMap from './DataMap.js';
 import DataMap from './DataMap.js';
-import { DepthTexture, DepthStencilFormat, UnsignedInt248Type } from 'three';
+import { Vector2, DepthTexture, DepthStencilFormat, UnsignedInt248Type } from 'three';
+
+const _size = new Vector2();
 
 
 class Textures extends DataMap {
 class Textures extends DataMap {
 
 
@@ -17,6 +19,7 @@ class Textures extends DataMap {
 		const renderTargetData = this.get( renderTarget );
 		const renderTargetData = this.get( renderTarget );
 
 
 		const texture = renderTarget.texture;
 		const texture = renderTarget.texture;
+		const size = this.getSize( texture );
 
 
 		let depthTexture = renderTarget.depthTexture || renderTargetData.depthTexture;
 		let depthTexture = renderTarget.depthTexture || renderTargetData.depthTexture;
 
 
@@ -25,23 +28,23 @@ class Textures extends DataMap {
 			depthTexture = new DepthTexture();
 			depthTexture = new DepthTexture();
 			depthTexture.format = DepthStencilFormat;
 			depthTexture.format = DepthStencilFormat;
 			depthTexture.type = UnsignedInt248Type;
 			depthTexture.type = UnsignedInt248Type;
-			depthTexture.image.width = texture.image.width;
-			depthTexture.image.height = texture.image.height;
+			depthTexture.image.width = size.width;
+			depthTexture.image.height = size.height;
 
 
 		}
 		}
 
 
-		if ( renderTargetData.width !== texture.image.width || texture.image.height !== renderTargetData.height ) {
+		if ( renderTargetData.width !== size.width || size.height !== renderTargetData.height ) {
 
 
 			texture.needsUpdate = true;
 			texture.needsUpdate = true;
 			depthTexture.needsUpdate = true;
 			depthTexture.needsUpdate = true;
 
 
-			depthTexture.image.width = texture.image.width;
-			depthTexture.image.height = texture.image.height;
+			depthTexture.image.width = size.width;
+			depthTexture.image.height = size.height;
 
 
 		}
 		}
 
 
-		renderTargetData.width = texture.image.width;
-		renderTargetData.height = texture.image.height;
+		renderTargetData.width = size.width;
+		renderTargetData.height = size.height;
 		renderTargetData.texture = texture;
 		renderTargetData.texture = texture;
 		renderTargetData.depthTexture = depthTexture;
 		renderTargetData.depthTexture = depthTexture;
 
 
@@ -171,6 +174,24 @@ class Textures extends DataMap {
 
 
 	}
 	}
 
 
+	getSize( texture, target = _size ) {
+
+		if ( texture.isCubeTexture ) {
+
+			target.width = texture.image[ 0 ].width;
+			target.height = texture.image[ 0 ].height;
+
+		} else {
+
+			target.width = texture.image.width;
+			target.height = texture.image.height;
+
+		}
+
+		return target;
+
+	}
+
 	_destroyTexture( texture ) {
 	_destroyTexture( texture ) {
 
 
 		this.backend.destroySampler( texture );
 		this.backend.destroySampler( texture );

+ 38 - 37
examples/jsm/renderers/common/nodes/Nodes.js

@@ -16,9 +16,9 @@ class Nodes extends DataMap {
 
 
 	getForRender( renderObject ) {
 	getForRender( renderObject ) {
 
 
-		const renderObjectProperties = this.get( renderObject );
+		const renderObjectData = this.get( renderObject );
 
 
-		let nodeBuilder = renderObjectProperties.nodeBuilder;
+		let nodeBuilder = renderObjectData.nodeBuilder;
 
 
 		if ( nodeBuilder === undefined ) {
 		if ( nodeBuilder === undefined ) {
 
 
@@ -30,7 +30,7 @@ class Nodes extends DataMap {
 			nodeBuilder.toneMappingNode = this.getToneMappingNode();
 			nodeBuilder.toneMappingNode = this.getToneMappingNode();
 			nodeBuilder.build();
 			nodeBuilder.build();
 
 
-			renderObjectProperties.nodeBuilder = nodeBuilder;
+			renderObjectData.nodeBuilder = nodeBuilder;
 
 
 		}
 		}
 
 
@@ -40,16 +40,16 @@ class Nodes extends DataMap {
 
 
 	getForCompute( computeNode ) {
 	getForCompute( computeNode ) {
 
 
-		const computeProperties = this.get( computeNode );
+		const computeData = this.get( computeNode );
 
 
-		let nodeBuilder = computeProperties.nodeBuilder;
+		let nodeBuilder = computeData.nodeBuilder;
 
 
 		if ( nodeBuilder === undefined ) {
 		if ( nodeBuilder === undefined ) {
 
 
 			nodeBuilder = this.backend.createNodeBuilder( computeNode, this.renderer );
 			nodeBuilder = this.backend.createNodeBuilder( computeNode, this.renderer );
 			nodeBuilder.build();
 			nodeBuilder.build();
 
 
-			computeProperties.nodeBuilder = nodeBuilder;
+			computeData.nodeBuilder = nodeBuilder;
 
 
 		}
 		}
 
 
@@ -110,22 +110,27 @@ class Nodes extends DataMap {
 	updateToneMapping() {
 	updateToneMapping() {
 
 
 		const renderer = this.renderer;
 		const renderer = this.renderer;
-		const rendererProperties = this.get( renderer );
+		const rendererData = this.get( renderer );
 		const rendererToneMapping = renderer.toneMapping;
 		const rendererToneMapping = renderer.toneMapping;
 
 
 		if ( rendererToneMapping !== NoToneMapping ) {
 		if ( rendererToneMapping !== NoToneMapping ) {
 
 
-			if ( rendererProperties.toneMapping !== rendererToneMapping ) {
+			if ( rendererData.toneMapping !== rendererToneMapping ) {
 
 
-				rendererProperties.toneMappingNode = toneMapping( rendererToneMapping, reference( 'toneMappingExposure', 'float', renderer ) );
-				rendererProperties.toneMapping = rendererToneMapping;
+				const rendererToneMappingNode = rendererData.rendererToneMappingNode || toneMapping( rendererToneMapping, reference( 'toneMappingExposure', 'float', renderer ) );
+				rendererToneMappingNode.toneMapping = rendererToneMapping;
+
+				rendererData.rendererToneMappingNode = rendererToneMappingNode;
+				rendererData.toneMappingNode = rendererToneMappingNode;
+				rendererData.toneMapping = rendererToneMapping;
 
 
 			}
 			}
 
 
 		} else {
 		} else {
 
 
-			delete rendererProperties.toneMappingNode;
-			delete rendererProperties.toneMapping;
+			// Don't delete rendererData.rendererToneMappingNode
+			delete rendererData.toneMappingNode;
+			delete rendererData.toneMapping;
 
 
 		}
 		}
 
 
@@ -133,12 +138,12 @@ class Nodes extends DataMap {
 
 
 	updateBackground( scene ) {
 	updateBackground( scene ) {
 
 
-		const sceneProperties = this.get( scene );
+		const sceneData = this.get( scene );
 		const background = scene.background;
 		const background = scene.background;
 
 
 		if ( background ) {
 		if ( background ) {
 
 
-			if ( sceneProperties.background !== background ) {
+			if ( sceneData.background !== background ) {
 
 
 				let backgroundNode = null;
 				let backgroundNode = null;
 
 
@@ -168,15 +173,15 @@ class Nodes extends DataMap {
 
 
 				}
 				}
 
 
-				sceneProperties.backgroundNode = backgroundNode;
-				sceneProperties.background = background;
+				sceneData.backgroundNode = backgroundNode;
+				sceneData.background = background;
 
 
 			}
 			}
 
 
-		} else if ( sceneProperties.backgroundNode ) {
+		} else if ( sceneData.backgroundNode ) {
 
 
-			delete sceneProperties.backgroundNode;
-			delete sceneProperties.background;
+			delete sceneData.backgroundNode;
+			delete sceneData.background;
 
 
 		}
 		}
 
 
@@ -184,12 +189,12 @@ class Nodes extends DataMap {
 
 
 	updateFog( scene ) {
 	updateFog( scene ) {
 
 
-		const sceneProperties = this.get( scene );
+		const sceneData = this.get( scene );
 		const fog = scene.fog;
 		const fog = scene.fog;
 
 
 		if ( fog ) {
 		if ( fog ) {
 
 
-			if ( sceneProperties.fog !== fog ) {
+			if ( sceneData.fog !== fog ) {
 
 
 				let fogNode = null;
 				let fogNode = null;
 
 
@@ -207,15 +212,15 @@ class Nodes extends DataMap {
 
 
 				}
 				}
 
 
-				sceneProperties.fogNode = fogNode;
-				sceneProperties.fog = fog;
+				sceneData.fogNode = fogNode;
+				sceneData.fog = fog;
 
 
 			}
 			}
 
 
 		} else {
 		} else {
 
 
-			delete sceneProperties.fogNode;
-			delete sceneProperties.fog;
+			delete sceneData.fogNode;
+			delete sceneData.fog;
 
 
 		}
 		}
 
 
@@ -223,12 +228,12 @@ class Nodes extends DataMap {
 
 
 	updateEnvironment( scene ) {
 	updateEnvironment( scene ) {
 
 
-		const sceneProperties = this.get( scene );
+		const sceneData = this.get( scene );
 		const environment = scene.environment;
 		const environment = scene.environment;
 
 
 		if ( environment ) {
 		if ( environment ) {
 
 
-			if ( sceneProperties.environment !== environment ) {
+			if ( sceneData.environment !== environment ) {
 
 
 				let environmentNode = null;
 				let environmentNode = null;
 
 
@@ -246,15 +251,15 @@ class Nodes extends DataMap {
 
 
 				}
 				}
 
 
-				sceneProperties.environmentNode = environmentNode;
-				sceneProperties.environment = environment;
+				sceneData.environmentNode = environmentNode;
+				sceneData.environment = environment;
 
 
 			}
 			}
 
 
-		} else if ( sceneProperties.environmentNode ) {
+		} else if ( sceneData.environmentNode ) {
 
 
-			delete sceneProperties.environmentNode;
-			delete sceneProperties.environment;
+			delete sceneData.environmentNode;
+			delete sceneData.environment;
 
 
 		}
 		}
 
 
@@ -286,11 +291,7 @@ class Nodes extends DataMap {
 
 
 	}
 	}
 
 
-	updateForCompute( computeNode ) {
-
-
-
-	}
+	updateForCompute( /*computeNode*/ ) { }
 
 
 	updateForRender( renderObject ) {
 	updateForRender( renderObject ) {
 
 

+ 18 - 4
examples/jsm/renderers/webgpu/WebGPUBackend.js

@@ -1,4 +1,4 @@
-import { GPUFeatureName, GPUTextureFormat, GPULoadOp, GPUStoreOp, GPUIndexFormat } from './utils/WebGPUConstants.js';
+import { GPUFeatureName, GPUTextureFormat, GPULoadOp, GPUStoreOp, GPUIndexFormat, GPUTextureViewDimension } from './utils/WebGPUConstants.js';
 
 
 import WebGPUNodeBuilder from './nodes/WGSLNodeBuilder.js';
 import WebGPUNodeBuilder from './nodes/WGSLNodeBuilder.js';
 import Backend from '../common/Backend.js';
 import Backend from '../common/Backend.js';
@@ -151,7 +151,13 @@ class WebGPUBackend extends Backend {
 
 
 			// @TODO: Support RenderTarget with antialiasing.
 			// @TODO: Support RenderTarget with antialiasing.
 
 
-			colorAttachment.view = textureData.texture.createView();
+			colorAttachment.view = textureData.texture.createView( {
+				baseMipLevel: 0,
+				mipLevelCount: 1,
+				baseArrayLayer: renderContext.activeCubeFace,
+				dimension: GPUTextureViewDimension.TwoD
+			} );
+
 			depthStencilAttachment.view = depthTextureData.texture.createView();
 			depthStencilAttachment.view = depthTextureData.texture.createView();
 
 
 			if ( renderContext.stencil && renderContext.depthTexture.format === DepthFormat ) {
 			if ( renderContext.stencil && renderContext.depthTexture.format === DepthFormat ) {
@@ -264,6 +270,14 @@ class WebGPUBackend extends Backend {
 
 
 		this.device.queue.submit( [ renderContextData.encoder.finish() ] );
 		this.device.queue.submit( [ renderContextData.encoder.finish() ] );
 
 
+		//
+
+		if ( renderContext.texture !== null && renderContext.texture.generateMipmaps === true ) {
+
+			this.textureUtils.generateMipmaps( renderContext.texture );
+
+		}
+
 	}
 	}
 
 
 	updateViewport( renderContext ) {
 	updateViewport( renderContext ) {
@@ -456,7 +470,7 @@ class WebGPUBackend extends Backend {
 
 
 		const utils = this.utils;
 		const utils = this.utils;
 
 
-		const sampleCount = utils.getSampleCount();
+		const sampleCount = utils.getSampleCount( renderObject.context );
 		const colorSpace = utils.getCurrentColorSpace( renderObject.context );
 		const colorSpace = utils.getCurrentColorSpace( renderObject.context );
 		const colorFormat = utils.getCurrentColorFormat( renderObject.context );
 		const colorFormat = utils.getCurrentColorFormat( renderObject.context );
 		const depthStencilFormat = utils.getCurrentDepthStencilFormat( renderObject.context );
 		const depthStencilFormat = utils.getCurrentDepthStencilFormat( renderObject.context );
@@ -490,7 +504,7 @@ class WebGPUBackend extends Backend {
 		const renderContext = renderObject.context;
 		const renderContext = renderObject.context;
 
 
 		return [
 		return [
-			utils.getSampleCount(),
+			utils.getSampleCount( renderContext ),
 			utils.getCurrentColorSpace( renderContext ), utils.getCurrentColorFormat( renderContext ), utils.getCurrentDepthStencilFormat( renderContext ),
 			utils.getCurrentColorSpace( renderContext ), utils.getCurrentColorFormat( renderContext ), utils.getCurrentDepthStencilFormat( renderContext ),
 			utils.getPrimitiveTopology( object, material )
 			utils.getPrimitiveTopology( object, material )
 		].join();
 		].join();

+ 7 - 0
examples/jsm/renderers/webgpu/nodes/WGSLNodeBuilder.js

@@ -11,6 +11,7 @@ import StorageBuffer from '../../common/StorageBuffer.js';
 import { getVectorLength, getStrideLength } from '../../common/BufferUtils.js';
 import { getVectorLength, getStrideLength } from '../../common/BufferUtils.js';
 
 
 import RenderTarget from '../../common/RenderTarget.js';
 import RenderTarget from '../../common/RenderTarget.js';
+import CubeRenderTarget from '../../common/CubeRenderTarget.js';
 
 
 import { NodeBuilder, CodeNode, NodeMaterial } from '../../../nodes/Nodes.js';
 import { NodeBuilder, CodeNode, NodeMaterial } from '../../../nodes/Nodes.js';
 
 
@@ -697,6 +698,12 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 
 	}
 	}
 
 
+	getCubeRenderTarget( size, options ) {
+
+		return new CubeRenderTarget( size, options );
+
+	}
+
 	getMethod( method ) {
 	getMethod( method ) {
 
 
 		if ( wgslPolyfill[ method ] !== undefined ) {
 		if ( wgslPolyfill[ method ] !== undefined ) {

+ 1 - 1
examples/jsm/renderers/webgpu/utils/WebGPUPipelineUtils.js

@@ -92,7 +92,7 @@ class WebGPUPipelineUtils {
 		const depthCompare = this._getDepthCompare( material );
 		const depthCompare = this._getDepthCompare( material );
 		const colorFormat = utils.getCurrentColorFormat( renderObject.context );
 		const colorFormat = utils.getCurrentColorFormat( renderObject.context );
 		const depthStencilFormat = utils.getCurrentDepthStencilFormat( renderObject.context );
 		const depthStencilFormat = utils.getCurrentDepthStencilFormat( renderObject.context );
-		const sampleCount = utils.getSampleCount();
+		const sampleCount = utils.getSampleCount( renderObject.context );
 
 
 		pipelineData.pipeline = device.createRenderPipeline( {
 		pipelineData.pipeline = device.createRenderPipeline( {
 			vertex: Object.assign( {}, vertexModule, { buffers: vertexBuffers } ),
 			vertex: Object.assign( {}, vertexModule, { buffers: vertexBuffers } ),

+ 36 - 4
examples/jsm/renderers/webgpu/utils/WebGPUTextureUtils.js

@@ -13,6 +13,8 @@ import {
 	NeverCompare, AlwaysCompare, LessCompare, LessEqualCompare, EqualCompare, GreaterEqualCompare, GreaterCompare, NotEqualCompare
 	NeverCompare, AlwaysCompare, LessCompare, LessEqualCompare, EqualCompare, GreaterEqualCompare, GreaterCompare, NotEqualCompare
 } from 'three';
 } from 'three';
 
 
+import { CubeReflectionMapping, CubeRefractionMapping, EquirectangularReflectionMapping, EquirectangularRefractionMapping } from 'three';
+
 import WebGPUTextureMipmapUtils from './WebGPUTextureMipmapUtils.js';
 import WebGPUTextureMipmapUtils from './WebGPUTextureMipmapUtils.js';
 
 
 const _compareToWebGPU = {
 const _compareToWebGPU = {
@@ -101,7 +103,7 @@ class WebGPUTextureUtils {
 		const dimension = this._getDimension( texture );
 		const dimension = this._getDimension( texture );
 		const mipLevelCount = this._getMipLevelCount( texture, width, height, needsMipmaps );
 		const mipLevelCount = this._getMipLevelCount( texture, width, height, needsMipmaps );
 		const format = texture.internalFormat || this._getFormat( texture );
 		const format = texture.internalFormat || this._getFormat( texture );
-		//const sampleCount = texture.isRenderTargetTexture || texture.isDepthTexture ? backend.utils.getSampleCount() : 1;
+		//const sampleCount = texture.isRenderTargetTexture || texture.isDepthTexture ? backend.utils.getSampleCount( renderContext ) : 1;
 		const sampleCount = 1;
 		const sampleCount = 1;
 
 
 		let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST;
 		let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST;
@@ -173,6 +175,26 @@ class WebGPUTextureUtils {
 
 
 	}
 	}
 
 
+	generateMipmaps( texture ) {
+
+		const textureData = this.backend.get( texture );
+
+		if ( texture.isCubeTexture ) {
+
+			for ( let i = 0; i < 6; i ++ ) {
+
+				this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU, i );
+
+			}
+
+		} else {
+
+			this._generateMipmaps( textureData.texture, textureData.textureDescriptorGPU );
+
+		}
+
+	}
+
 	updateTexture( texture ) {
 	updateTexture( texture ) {
 
 
 		const textureData = this.backend.get( texture );
 		const textureData = this.backend.get( texture );
@@ -223,6 +245,14 @@ class WebGPUTextureUtils {
 
 
 	}
 	}
 
 
+	_isEnvironmentTexture( texture ) {
+
+		const mapping = texture.mapping;
+
+		return ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) || ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping );
+
+	}
+
 	_getDefaultTextureGPU() {
 	_getDefaultTextureGPU() {
 
 
 		let defaultTexture = this.defaultTexture;
 		let defaultTexture = this.defaultTexture;
@@ -331,7 +361,7 @@ class WebGPUTextureUtils {
 
 
 	}
 	}
 
 
-	_generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer ) {
+	_generateMipmaps( textureGPU, textureDescriptorGPU, baseArrayLayer = 0 ) {
 
 
 		if ( this.mipmapUtils === null ) {
 		if ( this.mipmapUtils === null ) {
 
 
@@ -529,7 +559,9 @@ class WebGPUTextureUtils {
 
 
 	_needsMipmaps( texture ) {
 	_needsMipmaps( texture ) {
 
 
-		return ( texture.isCompressedTexture !== true ) && ( texture.generateMipmaps === true ) && ( texture.minFilter !== NearestFilter ) && ( texture.minFilter !== LinearFilter );
+		if ( this._isEnvironmentTexture( texture ) ) return true;
+
+		return ( texture.isCompressedTexture !== true ) /*&& ( texture.generateMipmaps === true )*/ && ( texture.minFilter !== NearestFilter ) && ( texture.minFilter !== LinearFilter );
 
 
 	}
 	}
 
 
@@ -595,7 +627,7 @@ class WebGPUTextureUtils {
 
 
 		let formatGPU;
 		let formatGPU;
 
 
-		if ( texture.isRenderTargetTexture === true || texture.isFramebufferTexture === true ) {
+		if ( /*texture.isRenderTargetTexture === true ||*/ texture.isFramebufferTexture === true ) {
 
 
 			formatGPU = GPUTextureFormat.BGRA8Unorm;
 			formatGPU = GPUTextureFormat.BGRA8Unorm;
 
 

+ 7 - 1
examples/jsm/renderers/webgpu/utils/WebGPUUtils.js

@@ -71,7 +71,13 @@ class WebGPUUtils {
 
 
 	}
 	}
 
 
-	getSampleCount() {
+	getSampleCount( renderContext ) {
+
+		if ( renderContext.texture !== null ) {
+
+			return 1;
+
+		}
 
 
 		return this.backend.parameters.sampleCount;
 		return this.backend.parameters.sampleCount;
 
 

BIN
examples/screenshots/webgl_materials_lightmap.jpg


BIN
examples/screenshots/webgl_nodes_loader_gltf_sheen.jpg


BIN
examples/screenshots/webgpu_cubemap_dynamic.jpg


+ 186 - 0
examples/webgpu_cubemap_dynamic.html

@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgpu - dynamic cube reflection</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="main.css">
+		<style>
+			body {
+				touch-action: none;
+			}
+		</style>
+	</head>
+	<body>
+
+		<div id="info"><a href="https://threejs.org" target="_blank" rel="noopener">three.js webgpu</a> - dynamic cube reflection</div>
+
+		<!-- Import maps polyfill -->
+		<!-- Remove this when import maps will be widely supported -->
+		<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.module.js",
+					"three/nodes": "./jsm/nodes/Nodes.js",
+					"three/addons/": "./jsm/"
+				}
+			}
+		</script>
+
+		<script type="module">
+
+			import * as THREE from 'three';
+			import * as Nodes from 'three/nodes';
+
+			import WebGPU from 'three/addons/capabilities/WebGPU.js';
+			import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
+
+			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+			import { RGBMLoader } from 'three/addons/loaders/RGBMLoader.js';
+
+			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
+			import Stats from 'three/addons/libs/stats.module.js';
+
+			let camera, scene, renderer, stats;
+			let cube, sphere, torus, material;
+
+			let cubeCamera, cubeRenderTarget;
+
+			let controls;
+
+			init();
+
+			function init() {
+
+				if ( WebGPU.isAvailable() === false ) {
+
+					document.body.appendChild( WebGPU.getErrorMessage() );
+
+					throw new Error( 'No WebGPU support' );
+
+				}
+
+				renderer = new WebGPURenderer( /*{ antialias: true }*/ );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.setAnimationLoop( animation );
+				renderer.toneMapping = THREE.ACESFilmicToneMapping;
+				document.body.appendChild( renderer.domElement );
+
+				window.addEventListener( 'resize', onWindowResized );
+
+				stats = new Stats();
+				document.body.appendChild( stats.dom );
+
+				camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera.position.z = 75;
+
+				scene = new THREE.Scene();
+
+				const uvTexture = new THREE.TextureLoader().load( './textures/uv_grid_opengl.jpg' );
+
+				const rgbmUrls = [ 'px.png', 'nx.png', 'py.png', 'ny.png', 'pz.png', 'nz.png' ];
+				const texture = new RGBMLoader()
+					.setMaxRange( 16 )
+					.setPath( './textures/cube/pisaRGBM16/' )
+					.loadCubemap( rgbmUrls );
+
+				texture.name = 'pisaRGBM16';
+				texture.minFilter = THREE.LinearMipmapLinearFilter;
+				texture.magFilter = THREE.LinearFilter;
+
+				scene.background = texture;
+				scene.environment = texture;
+
+				//
+
+				cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 256 );
+				cubeRenderTarget.texture.type = THREE.HalfFloatType;
+				cubeRenderTarget.texture.minFilter = THREE.LinearMipmapLinearFilter;
+				cubeRenderTarget.texture.magFilter = THREE.LinearFilter;
+				cubeRenderTarget.texture.generateMipmaps = true;
+
+				cubeCamera = new THREE.CubeCamera( 1, 1000, cubeRenderTarget );
+
+				//
+
+				material = new Nodes.MeshStandardNodeMaterial( {
+					envMap: cubeRenderTarget.texture,
+					roughness: 0.05,
+					metalness: 1
+				} );
+
+				const gui = new GUI();
+				gui.add( material, 'roughness', 0, 1 );
+				gui.add( material, 'metalness', 0, 1 );
+				gui.add( renderer, 'toneMappingExposure', 0, 2 ).name( 'exposure' );
+
+				sphere = new THREE.Mesh( new THREE.IcosahedronGeometry( 15, 8 ), material );
+				scene.add( sphere );
+
+				const material2 = new THREE.MeshStandardMaterial( {
+					map: uvTexture,
+					roughness: 0.1,
+					metalness: 0
+				} );
+
+				cube = new THREE.Mesh( new THREE.BoxGeometry( 15, 15, 15 ), material2 );
+				scene.add( cube );
+
+				torus = new THREE.Mesh( new THREE.TorusKnotGeometry( 8, 3, 128, 16 ), material2 );
+				scene.add( torus );
+
+				//
+
+				controls = new OrbitControls( camera, renderer.domElement );
+				controls.autoRotate = true;
+
+			}
+
+			function onWindowResized() {
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+			}
+
+			function animation( msTime ) {
+
+				const time = msTime / 1000;
+
+				cube.position.x = Math.cos( time ) * 30;
+				cube.position.y = Math.sin( time ) * 30;
+				cube.position.z = Math.sin( time ) * 30;
+
+				cube.rotation.x += 0.02;
+				cube.rotation.y += 0.03;
+
+				torus.position.x = Math.cos( time + 10 ) * 30;
+				torus.position.y = Math.sin( time + 10 ) * 30;
+				torus.position.z = Math.sin( time + 10 ) * 30;
+
+				torus.rotation.x += 0.02;
+				torus.rotation.y += 0.03;
+
+				material.visible = false;
+
+				cubeCamera.update( renderer, scene );
+
+				material.visible = true;
+
+				controls.update();
+
+				renderer.render( scene, camera );
+
+				stats.update();
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 3 - 1
examples/webgpu_loader_gltf.html

@@ -12,7 +12,7 @@
 			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - GLTFLoader<br />
 			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - GLTFLoader<br />
 			Battle Damaged Sci-fi Helmet by
 			Battle Damaged Sci-fi Helmet by
 			<a href="https://sketchfab.com/theblueturtle_" target="_blank" rel="noopener">theblueturtle_</a><br />
 			<a href="https://sketchfab.com/theblueturtle_" target="_blank" rel="noopener">theblueturtle_</a><br />
-			<a href="https://hdrihaven.com/hdri/?h=royal_esplanade" target="_blank" rel="noopener">Royal Esplanade</a> from <a href="https://hdrihaven.com/" target="_blank" rel="noopener">HDRI Haven</a>
+			<a href="https://hdrihaven.com/hdri/?h=royal_esplanade" target="_blank" rel="noopener">Royal Esplanade</a> by <a href="https://hdrihaven.com/" target="_blank" rel="noopener">HDRI Haven</a>
 		</div>
 		</div>
 
 
 		<!-- Import maps polyfill -->
 		<!-- Import maps polyfill -->
@@ -68,6 +68,8 @@
 					.load( 'royal_esplanade_1k.hdr', function ( texture ) {
 					.load( 'royal_esplanade_1k.hdr', function ( texture ) {
 
 
 						texture.mapping = THREE.EquirectangularReflectionMapping;
 						texture.mapping = THREE.EquirectangularReflectionMapping;
+						//texture.minFilter = THREE.LinearMipmapLinearFilter;
+						//texture.generateMipmaps = true;
 
 
 						scene.background = texture;
 						scene.background = texture;
 						scene.environment = texture;
 						scene.environment = texture;

+ 76 - 13
src/cameras/CubeCamera.js

@@ -1,4 +1,4 @@
-import { NoToneMapping } from '../constants.js';
+import { NoToneMapping, WebGLCoordinateSystem, WebGPUCoordinateSystem } from '../constants.js';
 import { Object3D } from '../core/Object3D.js';
 import { Object3D } from '../core/Object3D.js';
 import { PerspectiveCamera } from './PerspectiveCamera.js';
 import { PerspectiveCamera } from './PerspectiveCamera.js';
 
 
@@ -14,51 +14,114 @@ class CubeCamera extends Object3D {
 		this.type = 'CubeCamera';
 		this.type = 'CubeCamera';
 
 
 		this.renderTarget = renderTarget;
 		this.renderTarget = renderTarget;
+		this.coordinateSystem = null;
 
 
 		const cameraPX = new PerspectiveCamera( fov, aspect, near, far );
 		const cameraPX = new PerspectiveCamera( fov, aspect, near, far );
 		cameraPX.layers = this.layers;
 		cameraPX.layers = this.layers;
-		cameraPX.up.set( 0, 1, 0 );
-		cameraPX.lookAt( 1, 0, 0 );
 		this.add( cameraPX );
 		this.add( cameraPX );
 
 
 		const cameraNX = new PerspectiveCamera( fov, aspect, near, far );
 		const cameraNX = new PerspectiveCamera( fov, aspect, near, far );
 		cameraNX.layers = this.layers;
 		cameraNX.layers = this.layers;
-		cameraNX.up.set( 0, 1, 0 );
-		cameraNX.lookAt( - 1, 0, 0 );
 		this.add( cameraNX );
 		this.add( cameraNX );
 
 
 		const cameraPY = new PerspectiveCamera( fov, aspect, near, far );
 		const cameraPY = new PerspectiveCamera( fov, aspect, near, far );
 		cameraPY.layers = this.layers;
 		cameraPY.layers = this.layers;
-		cameraPY.up.set( 0, 0, - 1 );
-		cameraPY.lookAt( 0, 1, 0 );
 		this.add( cameraPY );
 		this.add( cameraPY );
 
 
 		const cameraNY = new PerspectiveCamera( fov, aspect, near, far );
 		const cameraNY = new PerspectiveCamera( fov, aspect, near, far );
 		cameraNY.layers = this.layers;
 		cameraNY.layers = this.layers;
-		cameraNY.up.set( 0, 0, 1 );
-		cameraNY.lookAt( 0, - 1, 0 );
 		this.add( cameraNY );
 		this.add( cameraNY );
 
 
 		const cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
 		const cameraPZ = new PerspectiveCamera( fov, aspect, near, far );
 		cameraPZ.layers = this.layers;
 		cameraPZ.layers = this.layers;
-		cameraPZ.up.set( 0, 1, 0 );
-		cameraPZ.lookAt( 0, 0, 1 );
 		this.add( cameraPZ );
 		this.add( cameraPZ );
 
 
 		const cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
 		const cameraNZ = new PerspectiveCamera( fov, aspect, near, far );
 		cameraNZ.layers = this.layers;
 		cameraNZ.layers = this.layers;
-		cameraNZ.up.set( 0, 1, 0 );
-		cameraNZ.lookAt( 0, 0, - 1 );
 		this.add( cameraNZ );
 		this.add( cameraNZ );
 
 
 	}
 	}
 
 
+	updateCoordinateSystem() {
+
+		const coordinateSystem = this.coordinateSystem;
+
+		const cameras = this.children.concat();
+
+		const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras;
+
+		for ( const camera of cameras ) this.remove( camera );
+
+		if ( coordinateSystem === WebGLCoordinateSystem ) {
+
+			cameraPX.up.set( 0, 1, 0 );
+			cameraPX.lookAt( 1, 0, 0 );
+
+			cameraNX.up.set( 0, 1, 0 );
+			cameraNX.lookAt( - 1, 0, 0 );
+
+			cameraPY.up.set( 0, 0, - 1 );
+			cameraPY.lookAt( 0, 1, 0 );
+
+			cameraNY.up.set( 0, 0, 1 );
+			cameraNY.lookAt( 0, - 1, 0 );
+
+			cameraPZ.up.set( 0, 1, 0 );
+			cameraPZ.lookAt( 0, 0, 1 );
+
+			cameraNZ.up.set( 0, 1, 0 );
+			cameraNZ.lookAt( 0, 0, - 1 );
+
+		} else if ( coordinateSystem === WebGPUCoordinateSystem ) {
+
+			cameraPX.up.set( 0, - 1, 0 );
+			cameraPX.lookAt( - 1, 0, 0 );
+
+			cameraNX.up.set( 0, - 1, 0 );
+			cameraNX.lookAt( 1, 0, 0 );
+
+			cameraPY.up.set( 0, 0, 1 );
+			cameraPY.lookAt( 0, 1, 0 );
+
+			cameraNY.up.set( 0, 0, - 1 );
+			cameraNY.lookAt( 0, - 1, 0 );
+
+			cameraPZ.up.set( 0, - 1, 0 );
+			cameraPZ.lookAt( 0, 0, 1 );
+
+			cameraNZ.up.set( 0, - 1, 0 );
+			cameraNZ.lookAt( 0, 0, - 1 );
+
+		} else {
+
+			throw new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem );
+
+		}
+
+		for ( const camera of cameras ) {
+
+			this.add( camera );
+
+			camera.updateMatrixWorld();
+
+		}
+
+	}
+
 	update( renderer, scene ) {
 	update( renderer, scene ) {
 
 
 		if ( this.parent === null ) this.updateMatrixWorld();
 		if ( this.parent === null ) this.updateMatrixWorld();
 
 
 		const renderTarget = this.renderTarget;
 		const renderTarget = this.renderTarget;
 
 
+		if ( this.coordinateSystem !== renderer.coordinateSystem ) {
+
+			this.coordinateSystem = renderer.coordinateSystem;
+
+			this.updateCoordinateSystem();
+
+		}
+
 		const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children;
 		const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children;
 
 
 		const currentRenderTarget = renderer.getRenderTarget();
 		const currentRenderTarget = renderer.getRenderTarget();

+ 1 - 0
test/e2e/puppeteer.js

@@ -96,6 +96,7 @@ const exceptionList = [
 	'webgpu_backdrop',
 	'webgpu_backdrop',
 	'webgpu_compute',
 	'webgpu_compute',
 	'webgpu_cubemap_adjustments',
 	'webgpu_cubemap_adjustments',
+	'webgpu_cubemap_dynamic',
 	'webgpu_cubemap_mix',
 	'webgpu_cubemap_mix',
 	'webgpu_depth_texture',
 	'webgpu_depth_texture',
 	'webgpu_equirectangular',
 	'webgpu_equirectangular',