仓库
思路:
渲染一个遮罩 亮的区域为需要显示另一个场景的区域
在靠近门时完全渲染一个场景 在穿过门的同时切换场景关系
if (this.Doors.length) {
// 材质变为黑色 除了“门”
toggleRoughnessMaterial("black");
// 设置RenderTarget保存结果
renderer.setRenderTarget(doorsRenderTarget);
// 渲染
render(this.helper.scene, this.helper.camera);
// 获取“门”的区域是否占满全屏
const region = this.getDoorRegion(fullWidth - 1, fullHeight - 1);
if (region == 1) {
// 当前的方式
const curr = moebiusPass.reversalTag;
// 切换对应渲染方式
moebiusPass.reversal = curr == "1" ? "2" : "1";
}
// 验证时候穿过门 并切换场景
PassedDoor();
// 重置RenderTarget
renderer.setRenderTarget(null);
// 材质切换回来
scene.toggleRoughnessMaterial("default");
// 隐藏“门”
this.Doors.forEach((obj: any) => (obj.visible = false));
}
获取穿梭门的渲染范围在屏幕中的占比
getDoorRegion(fullWidth: number, fullHeight: number) {
// 采样颜色平均值 判断距离
const _gl = this.helper.renderer.getContext() as WebGL2RenderingContext;
const pixels = new Uint8Array(4 * 1 * 1);
const count = 2;
const ratio = 1 / (count - 1);
let total = 0;
// 左下角开始
for (let i = 0; i < count; i++) {
for (let j = 0; j < count; j++) {
_gl.readPixels(
fullWidth * i * ratio,
fullHeight * j * ratio,
1,
1,
_gl.RGBA,
_gl.UNSIGNED_BYTE,
pixels
);
total += pixels[0];
total += pixels[1];
total += pixels[2];
}
}
total /= count * count * 255 * 3;
return total;
}
判断是否穿过门和方向
const PassedDoor = () => {
const nearDoor = this.Doors.map((door) => {
const distance = door.position.distanceTo(this.helper.camera.position);
door.userData.distance = distance;
return distance;
});
// 找到最小的一项的索引
const minIndex = nearDoor.reduce(
(minIdx, currentValue, currentIndex, arr) => (currentValue < arr[minIdx] ? currentIndex : minIdx),
0
);
// 最近的门
const door = this.Doors[minIndex];
// 离得远不进行计算
if (door.userData.distance > 2) {
this.dir = -1;
this.passed = false;
return;
}
cameraWorldPosition.setFromMatrixPosition(this.helper.camera.matrixWorld);
rotationMatrix.extractRotation(door.matrixWorld);
normal.set(0, 1, 0);
// normal.set(0, 0, 1);
normal.applyMatrix4(rotationMatrix);
const doorWorldPos = door.getWorldPosition(new THREE.Vector3());
view.subVectors(doorWorldPos, cameraWorldPosition);
// console.log(view.normalize().dot(normal.normalize()) > 0);
const front = +(view.normalize().dot(normal.normalize()) < 0);
if (this.dir != -1 && this.dir != front) {
console.log("Passed");
moebiusPass.reversal = moebiusPass.reversal == "1" ? "mix1" : "mix2";
moebiusPass.reversalTag = moebiusPass.reversalTag == "1" ? "2" : "1";
moebiusPass.setITime(0);
}
this.dir = front;
// console.log(this.dir);
};