주변 환경을 비추는 객체 표현

환경맵(envmap)을 사용해서 주변 환경의 모습을 비추는 객체를 표현할 때 적용할 수 있는 코드입니다. 먼저 아무런 재질도 적용되지 않은 검정색 구체입니다.

위의 검정색 구에 주변 환경 이미지를 환경 맵 소스로 활용하는 코드는 다음과 같습니다.

const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 1024 );
this._mirrorSphereCamera = new THREE.CubeCamera( 0.05, 50, cubeRenderTarget );
this._scene.add( this._mirrorSphereCamera );
const mirrorSphereMaterial = new THREE.MeshBasicMaterial( { envMap: cubeRenderTarget.texture } );
this._sphere.material = mirrorSphereMaterial;

환경맵을 생성하는 CubeCamera 객체의 상태가 변경될 경우… 예를들어 카메라의 위치 등이 변경될 경우 다음처럼 update 매서드를 호출해줘야 합니다.

this._mirrorSphereCamera.update( this._renderer, this._scene );

이 글에 사용된 코드와 결과는 Three.js에서 제공되는 예제 코드 중 webgl_animation_skinning_ik.html에서 환경맵 적용에 대한 내용만을 정리한 것입니다.

three.js의 RenderTarget 주요 코드 (WebGLRenderTarget)

이 글은 제가 추후 개발시 참조하기 위해 정리한 글로 설명이 매우 함축적일 수 있습니다.

three.js의 RenderTarget은 WebGLRenderTarget 타입으로 Texture 객체를 내부적으로 가지고 있는데, 이 Texture에 장면을 렌더링할 수 있다. 이름이 RenderTarget인 이유는 three.js의 렌더러(Renderer)의 렌더링 대상으로 지정될 수 있기 때문이며 렌더링 대상으로 지정하기 위해 사용되는 메서드는 setRenderTarget이다.

주요 코드를 정리한다. RenderTarget 객체를 생성하고 이 RenderTarget에 그려넣을 장면과 카메라 등을 준비하는 코드다.

_setupRenderTargets() {
    const rtSize = new THREE.Vector2(1024, 1024);
    const renderTarget = new THREE.WebGLRenderTarget(
        rtSize.width, rtSize.height, 
        {
            depthBuffer: false, stencilBuffer: false
        }
    );

    const fov = 75;
    const aspect = rtSize.width / rtSize.height;
    const near = 0.1;
    const far = 5;
    const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
    camera.position.z = 4;
        
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0x444444);

    const color = 0xffffff;
    const intensity = 1;
    const light = new THREE.DirectionalLight(color, intensity);
    light.position.set(-1, 2, 4);
    scene.add(light);

    const geometry = new THREE.BoxGeometry(1,4,1);
    const makeInstance = (color, x) => {
        const material = new THREE.MeshPhongMaterial({ color });
        const cube = new THREE.Mesh(geometry, material);
        scene.add(cube);
        cube.position.x = x;
        return cube;
    };

    const cubes = [
        makeInstance(0xff0000, -2),
        makeInstance(0x00ff00, 0),
        makeInstance(0x0000ff, 2),
    ];

    this._renderTargetsObject = { camera, scene, renderTarget, cubes };
}

RenderTarget은 Texture로 사용될 수 있으므로 다음처럼 재질의 map 속성의 값으로 지정될 수 있다.

const material = new THREE.MeshPhongMaterial({ 
    map: this._renderTargetsObject.renderTarget.texture 
});

RenderTarget도 렌더러에 의해 렌더링되어야 하므로 다음 코드가 필요하다.

this._renderer.setRenderTarget(this._renderTargetsObject.renderTarget);
this._renderer.render(this._renderTargetsObject.scene, this._renderTargetsObject.camera);
this._renderer.setRenderTarget(null);

결과는 다음과 같다.