<!-- NEW6 — TEST 6 · THE FIVE SHORES · part 352 -->
			this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? -1 : 1;

		} else {

			if ( this._equirectMaterial === null ) {

				this._equirectMaterial = _getEquirectMaterial();

			}

		}

		const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial;

		const mesh = this._lodMeshes[ 0 ];
		mesh.material = material;

		const uniforms = material.uniforms;

		uniforms[ 'envMap' ].value = texture;

		const size = this._cubeSize;

		_setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size );

		renderer.setRenderTarget( cubeUVRenderTarget );
		renderer.render( mesh, _flatCamera );

	}

	_applyPMREM( cubeUVRenderTarget ) {

		const renderer = this._renderer;
		const autoClear = renderer.autoClear;
		renderer.autoClear = false;

		const n = this._lodMeshes.length;

		// Use GGX VNDF importance sampling
		for ( let i = 1; i < n; i ++ ) {

			this._applyGGXFilter( cubeUVRenderTarget, i - 1, i );

		}

		renderer.autoClear = autoClear;

	}

	/**
	 * Applies GGX VNDF importance sampling filter to generate a prefiltered environment map.
	 * Uses Monte Carlo integration with VNDF importance sampling to accurately represent the
	 * GGX BRDF for physically-based rendering. Reads from the previous LOD level and
	 * applies incremental roughness filtering to avoid over-blurring.
	 *
	 * @private
	 * @param {WebGLRenderTarget} cubeUVRenderTarget
	 * @param {number} lodIn - Source LOD level to read from
	 * @param {number} lodOut - Target LOD level to write to
	 */
	_applyGGXFilter( cubeUVRenderTarget, lodIn, lodOut ) {

		const renderer = this._renderer;
		const pingPongRenderTarget = this._pingPongRenderTarget;

		const ggxMaterial = this._ggxMaterial;
		const ggxMesh = this._lodMeshes[ lodOut ];
		ggxMesh.material = ggxMaterial;

		const ggxUniforms = ggxMaterial.uniforms;

		// Calculate incremental roughness between LOD levels
		const targetRoughness = lodOut / ( this._lodMeshes.length - 1 );
		const sourceRoughness = lodIn / ( this._lodMeshes.length - 1 );
		const incrementalRoughness = Math.sqrt( targetRoughness * targetRoughness - sourceRoughness * sourceRoughness );

		// Apply blur strength mapping for better quality across the roughness range
		const blurStrength = targetRoughness * 1.25;
		const adjustedRoughness = incrementalRoughness * blurStrength;

		// Calculate viewport position based on output LOD level
		const { _lodMax } = this;
		const outputSize = this._sizeLods[ lodOut ];
		const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 );
		const y = 4 * ( this._cubeSize - outputSize );

		// Read from previous LOD with incremental roughness
		ggxUniforms[ 'envMap' ].value = cubeUVRenderTarget.texture;
		ggxUniforms[ 'roughness' ].value = adjustedRoughness;
		ggxUniforms[ 'mipInt' ].value = _lodMax - lodIn; // Sample from input LOD

		_setViewport( pingPongRenderTarget, x, y, 3 * outputSize, 2 * outputSize );
		renderer.setRenderTarget( pingPongRenderTarget );
		renderer.render( ggxMesh, _flatCamera );

		// Copy from pingPong back to cubeUV (simple direct copy)
		ggxUniforms[ 'envMap' ].value = pingPongRenderTarget.texture;
		ggxUniforms[ 'roughness' ].value = 0.0; // Direct copy
		ggxUniforms[ 'mipInt' ].value = _lodMax - lodOut; // Read from the level we just wrote

		_setViewport( cubeUVRenderTarget, x, y, 3 * outputSize, 2 * outputSize );
		renderer.setRenderTarget( cubeUVRenderTarget );
		renderer.render( ggxMesh, _flatCamera );

	}

	/**
	 * This is a two-pass Gaussian blur for a cubemap. Each pass importance-samples
	 * the Gaussian along a spiral kernel (Golden Angle), which distributes samples
	 * isotropically on the sphere (no pole artifacts).
	 *
	 * Used for initial scene blur in fromScene() method when sigma > 0.
	 *
	 * @private
	 * @param {WebGLRenderTarget} cubeUVRenderTarget
	 * @param {number} lodIn
	 * @param {number} lodOut
	 * @param {number} sigma
	 */
	_blur( cubeUVRenderTarget, lodIn, lodOut, sigma ) {

		const pingPongRenderTarget = this._pingPongRenderTarget;

		// Two passes of sigma / sqrt( 2 ) compose to a blur of sigma while squaring
		// the effective sample count. Sigmas beyond PI are visually indistinguishable
		// from a uniform blur, so clamp to keep the shader math finite.
		const blurSigma = Math.min( sigma, Math.PI ) / Math.SQRT2;

		this._blurPass( cubeUVRenderTarget, pingPongRenderTarget, lodIn, lodOut, blurSigma );
		this._blurPass( pingPongRenderTarget, cubeUVRenderTarget, lodOut, lodOut, blurSigma );

	}

	_blurPass( targetIn, targetOut, lodIn, lodOut, sigmaRadians ) {

		const renderer = this._renderer;
		const blurMaterial = this._blurMaterial;

		const blurMesh = this._lodMeshes[ lodOut ];
		blurMesh.material = blurMaterial;

		const blurUniforms = blurMaterial.uniforms;

		blurUniforms[ 'envMap' ].value = targetIn.texture;
		blurUniforms[ 'sigma' ].value = sigmaRadians;
		blurUniforms[ 'mipInt' ].value = this._lo