여러 개의 카메라의 렌더링 결과를 하나의 장면에 표시해야할 필요가 생긴다. 예를들어 스타크래프트 게임을 보면 화면에 2개의 요소로 구분되어 있다. 첫째는 미니맵과 명령 아이콘들이 표시되는 커멘트 요소와 두번째는 실제 게임 플레이 요소이다. 이를 구현하는 방식은 여러가지가 있겠으나 멀티 카메라를 이용하는 방식이 있다. 게임 플레이 요소는 원근감 있게 PerspectiveCamera를 이용하고 커멘드 요소는 OrthographicCamera로 원근감 없이 렌더링하는 것이다. 이렇게 각 카메라로 렌더링되는 요소를 하나의 장면에 중첩해서 표시하면 된다.
마우스에 대한 상호작용은 Camera를 입력값을 개별 요소로 받으니 어떤 객체든 마우스 상호작용을 쉽게 얻을 수 있다. 이미 알고 있겠지만 Raycast를 이용해서 말이다. 여러개의 카메라를 사용할때 생각할 것은 어떤 요소를 어떤 카메라에 할당해 렌더링할 것인지에 대한 지정이다. 물론 하나의 요소를 여러개의 카메라에서 동시에 렌더링하는 것도 가능하다. 이러한 구분은 Layers라는 기능을 이용하면 매우 직관적으로 처리할 수 있다. three.js에서 Layers는 총 32개로 구성된다. 기본적으로 모든 카메라, 광원, 매시 등은 0번째 레이어에 소속된다. 어떤 카메라가 소속된 레이어와 동일한 레이어에 소속된 것들은 모두 카메라를 통해 렌더링된다.
이를 코드로 작성해 보자. 먼저 카메라 2개를 만들자. 쉽게 설명하기 위해 둘다 PerpectiveCamera 객체다.
_setupCamera() {
...
const aspect = width / height;
const camera1 = new THREE.PerspectiveCamera(60, aspect, 0.1, 10);
camera1.layers.enable(1);
camera1.position.z = 3;
this._camera1 = camera1;
const camera2 = new THREE.PerspectiveCamera(60, aspect, 0.1, 10);
camera2.layers.enable(2);
camera2.position.z = 2;
this._camera2 = camera2;
}
camera1과 camera2는 각각 0,1 레이어와 0,2 레이어에 소속되어 있다. 만약 camera1을 1번 레이어에만 소속시키려면 camera1.layers.set(1) 코드면 된다.
다음은 렌더링할 매시를 다음처럼 구성한다.
const geometryC1 = new THREE.BoxGeometry();
const materialC1 = new THREE.MeshStandardMaterial();
const meshC1 = new THREE.Mesh(geometryC1, materialC1);
meshC1.layers.set(1);
this._scene.add(meshC1);
const geometryC2 = new THREE.BoxGeometry();
const materialC2 = new THREE.MeshStandardMaterial({ wireframe: true });
const meshC2 = new THREE.Mesh(geometryC2, materialC2)
meshC2.layers.set(2);
this._scene.add(meshC2);
meshC1은 1 레이어에만 소속되어 있다. meshC2는 2 레이어에만 소속되어 있다. 만약 layers의 set 대신 enable를 사용하면 기본적으로 소속된 0번 레이어에 대한 소속은 그대로 유지되므로 명확히 1 번 레이어에만 소속되도록 set를 사용했다. 광원에 대한 layers 설정은 하지 않았으므로 0 레이어에 소속되어 있다. camera1과 camera2의 layers를 enable로 해서 설정했으므로 각 카메라는 기본적으로 소속된 0번 레이어에도 소속되어 있고 0 레이어에 소속된 광원의 영향을 2개 카메라 모두 사용하게 된다.
이제 렌더링과 관련된 코드를 작성해야 한다. 그전에 Renderer 객체에 대해 다음 코드가 필요하다.
renderer.autoClearColor = false;
기본적으로 장면이 렌더링 되기 직전에 자동으로 정해진 색상으로 프레임버퍼가 설정된다. 위의 코드는 이처럼 자동으로 이뤄지는 것을 방지하고자 함이다. 자, 이제 렌더링 코드를 보자.
render() {
this.update();
this._renderer.clearColor();
this._renderer.render(this._scene, this._camera2);
this._renderer.render(this._scene, this._camera1);
requestAnimationFrame(this.render.bind(this));
}
Renderer의 autoClearColor를 false로 지정했으므로 이제 직접 프레임버퍼를 지우기 위해 Renderer의 clearColor 매서드를 호출해야 한다. 그런 후에 각 카메라를 이용해 장면을 렌더링한다. 끝이다.
굳히 언급하지 않아도 이미 알겠지만 창 크기가 변경되면 카메라의 기저 인자값들을 재설정해줘야 한다. 카메라가 여러개이므로 이에 대한 코드까지 살펴보고 마무리 한다.
resize() {
...
const aspect = width / height;
this._camera1.aspect = aspect;
this._camera1.updateProjectionMatrix();
this._camera2.aspect = aspect;
this._camera2.updateProjectionMatrix();
...
}