在 Three.js 中处理多个场景可以通过以下几种方式实现:
// 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 创建多个场景
const scene1 = new THREE.Scene();
const scene2 = new THREE.Scene();
const scene3 = new THREE.Scene();
// 创建多个相机(可根据需要)
const camera1 = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const camera2 = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 给不同场景设置不同背景
scene1.background = new THREE.Color(0x000000);
scene2.background = new THREE.Color(0x111122);
scene3.background = new THREE.Color(0x221111);
function animate() {
requestAnimationFrame(animate);
// 清屏渲染第一个场景
renderer.autoClear = true;
renderer.render(scene1, camera1);
// 不清屏渲染第二个场景(叠加)
renderer.autoClear = false;
renderer.render(scene2, camera2);
// 继续渲染第三个场景
renderer.render(scene3, camera3);
// 重置为默认
renderer.autoClear = true;
}
function renderMultiViewport() {
const width = window.innerWidth;
const height = window.innerHeight;
// 场景1 - 左半部分
renderer.setViewport(0, 0, width/2, height);
renderer.setScissor(0, 0, width/2, height);
renderer.setScissorTest(true);
renderer.render(scene1, camera1);
// 场景2 - 右上半部分
renderer.setViewport(width/2, height/2, width/2, height/2);
renderer.setScissor(width/2, height/2, width/2, height/2);
renderer.render(scene2, camera2);
// 场景3 - 右下半部分
renderer.setViewport(width/2, 0, width/2, height/2);
renderer.setScissor(width/2, 0, width/2, height/2);
renderer.render(scene3, camera3);
// 重置视口
renderer.setViewport(0, 0, width, height);
renderer.setScissorTest(false);
}
// 创建渲染目标
const renderTarget1 = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
const renderTarget2 = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
function renderToTexture() {
// 将场景渲染到纹理
renderer.setRenderTarget(renderTarget1);
renderer.render(scene1, camera1);
renderer.setRenderTarget(renderTarget2);
renderer.render(scene2, camera2);
// 重置为默认渲染目标(屏幕)
renderer.setRenderTarget(null);
// 使用纹理创建平面显示
const planeMaterial = new THREE.MeshBasicMaterial({
map: renderTarget1.texture
});
const plane = new THREE.Mesh(new THREE.PlaneGeometry(5, 5), planeMaterial);
scene3.add(plane); // 在第三个场景中显示
}
class MultiSceneManager {
constructor() {
this.scenes = new Map();
this.currentScene = null;
this.renderer = null;
this.cameras = new Map();
}
init() {
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(this.renderer.domElement);
// 初始化场景
this.createScene('main', 0x000000);
this.createScene('ui', 0x000000);
this.createScene('background', 0x111122);
// 设置场景透明,支持叠加
this.scenes.get('ui').background = null;
this.renderer.autoClear = false;
// 设置初始场景
this.switchToScene('main');
}
createScene(name, bgColor) {
const scene = new THREE.Scene();
scene.name = name;
if (bgColor !== null) {
scene.background = new THREE.Color(bgColor);
}
// 为每个场景创建相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 5;
this.scenes.set(name, scene);
this.cameras.set(name, camera);
return { scene, camera };
}
switchToScene(sceneName) {
this.currentScene = sceneName;
}
render() {
requestAnimationFrame(() => this.render());
// 清屏
this.renderer.clear();
// 渲染背景场景
this.renderer.render(
this.scenes.get('background'),
this.cameras.get('background')
);
// 不清屏渲染主场景(叠加)
this.renderer.clearDepth(); // 清除深度缓冲区
this.renderer.render(
this.scenes.get(this.currentScene),
this.cameras.get(this.currentScene)
);
// 渲染UI场景(在最上层)
this.renderer.clearDepth();
this.renderer.render(
this.scenes.get('ui'),
this.cameras.get('ui')
);
}
getScene(name) {
return this.scenes.get(name);
}
getCamera(name) {
return this.cameras.get(name);
}
}
// 使用示例
const sceneManager = new MultiSceneManager();
sceneManager.init();
// 向不同场景添加对象
const mainScene = sceneManager.getScene('main');
const cube = new THREE.Mesh(
new THREE.BoxGeometry(),
new THREE.MeshBasicMaterial({ color: 0xff0000 })
);
mainScene.add(cube);
const uiScene = sceneManager.getScene('ui');
const uiText = new THREE.TextTexture('UI Element', { fontSize: 24 });
const uiPlane = new THREE.Mesh(
new THREE.PlaneGeometry(),
new THREE.MeshBasicMaterial({ map: uiText })
);
uiScene.add(uiPlane);
// 1. 按需渲染
class SelectiveRenderer {
constructor() {
this.activeScenes = new Set();
}
setSceneActive(name, active) {
if (active) {
this.activeScenes.add(name);
} else {
this.activeScenes.delete(name);
}
}
render(scenes, cameras) {
this.activeScenes.forEach(sceneName => {
renderer.render(scenes.get(sceneName), cameras.get(sceneName));
});
}
}
// 2. 共享资源
const sharedGeometry = new THREE.BoxGeometry();
const sharedMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });
const cube1 = new THREE.Mesh(sharedGeometry, sharedMaterial);
scene1.add(cube1);
const cube2 = new THREE.Mesh(sharedGeometry, sharedMaterial);
scene2.add(cube2);
// 3. 使用层次结构(替代多个场景)
const parentScene = new THREE.Scene();
const layer1 = new THREE.Group();
const layer2 = new THREE.Group();
layer1.name = 'background';
layer2.name = 'foreground';
parentScene.add(layer1);
parentScene.add(layer2);
// 单独控制不同层级的可见性
layer1.visible = true;
layer2.visible = true;
选择哪种方案取决于你的具体应用场景,通常组合使用多种技术可以获得最佳效果。