private initReflection()

in backup/renderers/renderer-gsi-gl2/src/GSIGL2Renderer.ts [671:920]


	private initReflection() {
		const canvasSize = this.renderer.getSize(new THREE.Vector2())
		const reflectionWidth = Math.floor(canvasSize.width * (this.props.reflectionRatio ?? 1.0))
		const reflectionHeight = Math.floor(canvasSize.height * (this.props.reflectionRatio ?? 1.0))
		const reflectionTexture = new THREE.WebGLRenderTarget(reflectionWidth, reflectionHeight, {
			minFilter: THREE.NearestFilter,
			magFilter: THREE.NearestFilter,
			format: THREE.RGBFormat,
			stencilBuffer: false,
			// depthBuffer: false,
		})
		reflectionTexture.texture.generateMipmaps = false

		const reflectionTextureFXAA = new THREE.WebGLRenderTarget(reflectionWidth, reflectionHeight, {
			minFilter: THREE.LinearFilter,
			magFilter: THREE.LinearFilter,
			format: THREE.RGBFormat,
			stencilBuffer: false,
			depthBuffer: false,
		})
		reflectionTextureFXAA.texture.generateMipmaps = false

		const reflectionTextureRough = new THREE.WebGLRenderTarget(
			reflectionWidth / 2,
			reflectionHeight / 2,
			{
				minFilter: THREE.LinearFilter,
				magFilter: THREE.LinearFilter,
				format: THREE.RGBFormat,
				stencilBuffer: false,
				depthBuffer: false,
			}
		)
		reflectionTextureRough.texture.generateMipmaps = false

		const reflectionCamera = new THREE.PerspectiveCamera()
		reflectionCamera.layers.disable(0)
		reflectionCamera.layers.enable(1)
		reflectionCamera.name = 'reflectionCamera'

		// 基础场景绘制
		const drawPass = new Pass(
			{
				// width: reflectionWidth,
				// height: reflectionHeight,
				scene: this.scene,
				camera: reflectionCamera,
			},
			THREE
		)
		drawPass.setOutput(reflectionTexture)

		// FXAA
		const fxaaPass = new FXAAPass(
			{
				width: reflectionWidth,
				height: reflectionHeight,
			},
			THREE
		)
		fxaaPass.setInput(reflectionTexture)
		fxaaPass.setOutput(reflectionTextureFXAA)

		// 模糊
		const blurPass = new BlurPass(
			{
				width: reflectionWidth,
				height: reflectionHeight,
				kernel: 3,
			},
			THREE
		)
		blurPass.setInput(reflectionTextureFXAA)
		blurPass.setOutput(reflectionTextureRough)

		// Reflector
		const reflector = new THREE.Mesh(
			new THREE.PlaneBufferGeometry(0, 0.001, 1, 1),
			new THREE.ShaderMaterial({
				name: 'Polaris::reflector',
			})
		)
		reflector.name = 'reflectTimer(only for updating reflection)'
		reflector.renderOrder = -Infinity
		reflector.frustumCulled = false
		reflector.visible = this.props.enableReflection ?? false
		this.scene.add(reflector)

		const clipBias = 0
		const reflectorPlane = new THREE.Plane()
		const normal = new THREE.Vector3(0, 1, 0)
		const reflectorWorldPosition = new THREE.Vector3()
		const rotationMatrix = new THREE.Matrix4()
		const clipPlane = new THREE.Vector4()
		const viewport = new THREE.Vector4()
		const view = new THREE.Vector3()
		const q = new THREE.Vector4()
		const origin = new THREE.Vector3()
		const reflectionTexMatrix = new THREE.Matrix4()

		reflector.onBeforeRender = () => {
			const renderer = this.renderer
			const camera = this.camera
			// const cam = this.cam

			view.copy(camera.position)
			view.y = -view.y

			// 按照Polaris的相机设计,视野中心应该总是000,除非相机整体偏移
			// origin.y = -cam.altOffset

			rotationMatrix.extractRotation(camera.matrixWorld)

			reflectionCamera.position.copy(view)
			reflectionCamera.up.set(0, 1, 0)
			reflectionCamera.up.applyMatrix4(rotationMatrix)
			reflectionCamera.up.reflect(normal)
			reflectionCamera.lookAt(origin)

			// reflectionCamera.far = camera.far + SETTINGS.SKY_SPHERE_RADIUS - this.config.skylineOffset; // Used in WebGLBackground
			reflectionCamera.far = camera.far // Used in WebGLBackground
			reflectionCamera.near = camera.near // Used in WebGLBackground
			reflectionCamera.updateMatrixWorld()

			// 避免天空盒超出far的范围
			// @NOTE 在THREE中时调整天空盒的尺寸,适应camera的far,但是由于我们需要调整天空盒的位置(skylineOffset), 不能调整天空盒的尺寸
			// @TODO
			// const oldFar = camera.far
			// camera.far += SETTINGS.SKY_SPHERE_RADIUS - this.config.skylineOffset
			// camera.updateProjectionMatrix()
			reflectionCamera.projectionMatrix.copy(camera.projectionMatrix)
			// camera.far = oldFar
			// camera.updateProjectionMatrix()

			// Update the texture matrix
			// prettier-ignore
			this.reflectionTexMatrix.set(
				0.5, 0.0, 0.0, 0.5,
				0.0, 0.5, 0.0, 0.5,
				0.0, 0.0, 0.5, 0.5,
				0.0, 0.0, 0.0, 1.0
			)
			this.reflectionTexMatrix.multiply(reflectionCamera.projectionMatrix)
			this.reflectionTexMatrix.multiply(reflectionCamera.matrixWorldInverse)
			// this.reflectionTexMatrix.multiply( this.reflector.matrixWorld );

			// Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
			// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
			reflectorPlane.setFromNormalAndCoplanarPoint(normal, reflectorWorldPosition) // 001, 000
			reflectorPlane.applyMatrix4(reflectionCamera.matrixWorldInverse)

			clipPlane.set(
				reflectorPlane.normal.x,
				reflectorPlane.normal.y,
				reflectorPlane.normal.z,
				reflectorPlane.constant
			)

			const projectionMatrix = reflectionCamera.projectionMatrix

			q.x = (Math.sign(clipPlane.x) + projectionMatrix.elements[8]) / projectionMatrix.elements[0]
			q.y = (Math.sign(clipPlane.y) + projectionMatrix.elements[9]) / projectionMatrix.elements[5]
			q.z = -1.0
			q.w = (1.0 + projectionMatrix.elements[10]) / projectionMatrix.elements[14]

			// Calculate the scaled plane vector
			clipPlane.multiplyScalar(2.0 / clipPlane.dot(q))

			// Replacing the third row of the projection matrix
			projectionMatrix.elements[2] = clipPlane.x
			projectionMatrix.elements[6] = clipPlane.y
			projectionMatrix.elements[10] = clipPlane.z + 1.0 - clipBias
			projectionMatrix.elements[14] = clipPlane.w

			// Render

			const currentRenderTarget = renderer.getRenderTarget() as THREE.WebGLRenderTarget

			const currentVrEnabled = renderer.vr.enabled
			const currentShadowAutoUpdate = renderer.shadowMap.autoUpdate

			// 反射过程中不计算阴影,节约性能
			const currCastShadow = this.props.castShadow
			// this.directionalLight.castShadow = false

			renderer.vr.enabled = false // Avoid camera modification and recursion
			renderer.shadowMap.autoUpdate = false // Avoid re-computing shadows

			// 天空盒位置调整
			// this.skylineAnchor.position.z = 0
			// this.skylineAnchor.position.y = this.skylineOffset
			// reflectionCamera.add(this.skylineAnchor)
			// this.skylineAnchor.updateMatrixWorld()
			// this.skySphere.matrixWorld.copyPosition(this.skylineAnchor.matrixWorld)
			// this.skySphere.matrixWorld.copyPosition(camera.matrixWorld)
			//

			// renderer.render( scene, reflectionCamera, this.reflectionTexture, true );
			renderer.autoClear = true
			drawPass.render(renderer)

			// this.directionalLight.castShadow = currCastShadow

			// blurPass.render(this.renderer, this.reflectionTexture, this.reflectionTextureBlur)
			renderer.autoClear = false
			// const _size = renderer.getSize()
			// this.renderer.setSize(512, 512, false)

			// composerFXAA.render()
			// composer.render()

			// this.pipeline.render()
			// NOTE TODO 不这样做的话似乎会有不clear的情况
			renderer.autoClear = true
			fxaaPass.render(renderer)
			this.renderer.autoClear = false
			blurPass.render(renderer)

			this.renderer.autoClear = true
			// this.renderer.setSize(_size.width, _size.height, false)

			renderer.vr.enabled = currentVrEnabled
			renderer.shadowMap.autoUpdate = currentShadowAutoUpdate
			renderer.setRenderTarget(currentRenderTarget)

			// Restore viewport
			const bounds = camera['bounds']

			if (bounds !== undefined) {
				const size = renderer.getSize(new THREE.Vector2())
				const pixelRatio = renderer.getPixelRatio()

				viewport.x = bounds.x * size.width * pixelRatio
				viewport.y = bounds.y * size.height * pixelRatio
				viewport.z = bounds.z * size.width * pixelRatio
				viewport.w = bounds.w * size.height * pixelRatio

				renderer.state.viewport(viewport)
			}
		}

		this.reflectionTexture = reflectionTexture
		this.reflectionTextureFXAA = reflectionTextureFXAA
		this.reflectionTextureRough = reflectionTextureRough
		this.reflectionDrawPass = drawPass
		this.reflectionFxaaPass = fxaaPass
		this.reflectionBlurPass = blurPass
		this.reflector = reflector
		this.reflectionTexMatrix = reflectionTexMatrix
	}