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
}