Three.js/기초튼튼

three.js GUI Controls - lil-gui, addFolder, geometry.dispose

carrotweb 2023. 8. 27. 20:40
728x90
반응형

이전에 만든 Controls에 아래의 three.js 사이트의 doc 처럼 SphereGeometry(스피어 지오메트리, 구 기하 도형)에 대한 속성들을 추가해 보겠습니다. (https://threejs.org/docs/index.html#api/en/geometries/SphereGeometry)

 

 

우선 Camera(카메라)의 위치(position)를 구 객체(sphere1) 앞으로 이동시키겠습니다.

 

현재 OrbitControls(오빗 컨트롤, 궤도 컨트롤)를 사용하고 있습니다. 그래서 항상 Camera(카메라)의 Focus Point(포커스 포인트, 초점)가 {x: 0, y: 0, z: 0} 입니다.

console.log(controls.target);
--> Vector3 {x: 0, y: 0, z: 0}

(OrbitControls(오빗 컨트롤, 궤도 컨트롤)를 사용하면 Camera(카메라)의 lookAt 함수를 사용해도 적용되지 않습니다.)

 

우선 Camera(카메라)의 Focus Point(포커스 포인트, 초점)을 구 객체(sphere1)의 위치로 조정하겠습니다.

console.log(sphere1.position);
--> Vector3 {x: 2, y: 1, z: -2}

 

OrbitControls(오빗 컨트롤, 궤도 컨트롤)의 target에 구 객체(sphere1)의 위치 값을 복사하거나 Vector3(백터)로 위치 값을 생성하여 설정합니다.

// 카메라 초점 변경
controls.target.copy(sphere1.position);

또는

// 카메라 초점 변경
controls.target = new THREE.Vector3(2, 1, -2);

 

그러면 Camera(카메라)의 Focus Point(포커스 포인트, 초점)가 구 객체(sphere1)의 위치로 변경됩니다.

 

만약, OrbitControls(오빗 컨트롤, 궤도 컨트롤)의 target에 구 객체(sphere1)의 위치 값을 바로 사용하면 OrbitControls(오빗 컨트롤, 궤도 컨트롤)에서 오른쪽 마우스로 Camera(카메라)의 위치를 변경하면 구 객체(sphere1)가 항상 중앙에 위치하게 되어 라인 세그먼트즈  객체와 분리되는 문제가 발생합니다.

controls.target = sphere1.position;

 

화면에 구 객체(sphere1)가 크게 보이도록 Camera(카메라)의 위치(position)를 조정합니다.

// 카메라 위치 변경
camera.position.set(2, 2.5, -1);

 

구 객체(sphere1)와 라인 세그먼트즈 객체(sphere1WireframeLine)는 구 그룹(sphere1Group)으로 구성되어 있습니다.

 

구 그룹(sphere1Group)의 첫 번째 자식은 구 객체(sphere1)이고 두 번째 자식은 와이어프레임을 선으로 그린 세그먼트즈 객체(sphere1WireframeLine)입니다.

console.log(sphere1Group.children);

 

라인 세그먼트즈 객체(sphere1WireframeLine)는 와이어프레임 지오메트리(sphere1WireframeGeometry)를 parameters(파라미터)로 전달받아 선으로 그립니다. 그리고  와이어프레임 지오메트리(sphere1WireframeGeometry)는 parameters(파라미터)로 구 지오메트리(sphere1Geometry)를 전달받아 와이어프레임을 생성합니다.

 

위에서 말한 것처럼 parameters(파라미터) 값으로 전달받기 때문에 값을 변경하여도 생성된 객체는 변경되지 않습니다.

console.log(sphere1Group.children[1].geometry.parameters.geometry.parameters.heightSegments);
--> 32

sphere1Group.children[1].geometry.parameters.geometry.parameters.heightSegments = 4;

console.log(sphere1Group.children[1].geometry.parameters.geometry.parameters.heightSegments);
--> 4

즉, 객체를 생성할 때 사용된 정보들은 객체 생성 후 변경되어도 다시 Rendering(렌더링)되지 않습니다.

 

 

그래서 Scence(씬, 장면)에 객체를 제거하고 객체를 폐기(Dispose)하고 다시 생성해서 Scence(씬, 장면)에 객체를 추가하면 됩니다. 그러나 너무 번거롭습니다.

 

그래서 쉽게 처리하는 방법으로 객체의 Geometry(지오메트리, 기하 도형)만 폐기(Dispose)하고 변경되는 정보로 생성하여 객체의 Geometry(지오메트리, 기하 도형)에 적용하는 겁니다.

 

그럼 테스트를 통해 확인해 보겠습니다.

 

1. 구 그룹(sphere1Group)에 있는 구 객체(sphere1)와 라인 세그먼트즈 객체(sphere1WireframeLine)의 Geometry(지오메트리, 기하 도형)를 폐기(Dispose)합니다.

// 적용된 지오메트리 폐기
sphere1Group.children[0].geometry.dispose();
sphere1Group.children[1].geometry.dispose();

 

2. 새로운 SphereGeometry(스피어 지오메트리, 구 기하 도형)의 radius(반지름, 반경)는 기존과 동일하게 1로 하고 widthSegments(수평 세그먼트, 가로 분절 수)와 heightSegments(수직 세그먼트, 세로 분절 수)는 10으로 설정하여 생성합니다.

// 새로운 지오메트리 생성
const sphere2Geometry = new THREE.SphereGeometry(1, 10, 10);

 

3. 새롭게 생성된  지오메트리(sphere2Geometry)를 구 객체(sphere1)의 Geometry(지오메트리, 기하 도형)에 적용시키고 라인 세그먼트즈 객체(sphere1WireframeLine)의 Geometry(지오메트리, 기하 도형)에는  지오메트리(sphere2Geometry)로 새로운 WireframeGeometry(와이어프레임 지오메트리)를 생성하여 적용시킵니다.

// 새로운 지오메트리 적용
sphere1Group.children[0].geometry = sphere2Geometry;
sphere1Group.children[1].geometry = new THREE.WireframeGeometry(sphere2Geometry);

 

그러면 변경된 정보로 변경되는 것을 확인할 수 있습니다.

 

만약,  그룹(sphere1Group)에 있는 구 객체(sphere1)의 Geometry(지오메트리, 기하 도형)는 변경하지 않고 라인 세그먼트즈 객체(sphere1WireframeLine)의 Geometry(지오메트리, 기하 도형)만 변경한다면 구의 객체의 모양과 와이어프레임 모양이 다르기 때문에 와이어프레임 선들이 구의 객체 안으로 들어가게 됩니다.

// 적용된 지오메트리 폐기
//sphere1Group.children[0].geometry.dispose();
sphere1Group.children[1].geometry.dispose();

// 새로운 지오메트리 생성
const sphere2Geometry = new THREE.SphereGeometry(1, 10, 10);

// 새로운 지오메트리 적용
//sphere1Group.children[0].geometry = sphere2Geometry;
sphere1Group.children[1].geometry = new THREE.WireframeGeometry(sphere2Geometry);

 

그럼 Controls에 SphereGeometry(스피어 지오메트리, 구 기하 도형)의 속성들을 컨트롤러로 추가해 보겠습니다.

 

위에서 테스트한 것처럼 매번 새로운 SphereGeometry(스피어 지오메트리, 구 기하 도형)를 생성해야 하기 때문에 parameters(파라미터)들을 별도의 객체로 관리해야 합니다.

 

1. SphereGeometry(스피어 지오메트리, 구 기하 도형)를 생성할 때 사용되는 parameters(파라미터)들로 객체(dataSphere1)를 만듭니다. (기본값으로 설정했습니다.)

const dataSphere1 = {
    radius: 1,
    widthSegments: 32,
    heightSegments: 16,
    phiStart: 0,
    phiLength: Math.PI * 2,
    thetaStart: 0,
    thetaLength: Math.PI
};

 

2. SphereGeometry(스피어 지오메트리, 구 기하 도형)의 parameters(파라미터)를 객체(dataSphere1)로 변경합니다.

const sphere1Geometry = new THREE.SphereGeometry(dataSphere1.radius, dataSphere1.widthSegments, dataSphere1.heightSegments, dataSphere1.phiStart, dataSphere1.phiLength, dataSphere1.thetaStart, dataSphere1.thetaLength);

 

3. Material(머티리얼)에서 구 객체의 안쪽에도 렌더링 되도록 side 속성을 THREE.DoubleSide로 추가합니다.

const sphere1Material = new THREE.MeshStandardMaterial({color: 0x0000ff, side: THREE.DoubleSide});

 

4.  그룹(sphere1Group)에 있는 구 객체(sphere1)와 라인 세그먼트즈 객체(sphere1WireframeLine)의 Geometry(지오메트리, 기하 도형)를 폐기(Dispose)하고 새로운 SphereGeometry(스피어 지오메트리, 구 기하 도형)를 생성하여 적용시키는 함수를 만듭니다.

// 구 그룹 지오메트리 변경 함수
function updatesShereGroupGeometry() {

    sphere1Group.children[0].geometry.dispose();
    sphere1Group.children[1].geometry.dispose();

    const newSphereGeometry = new THREE.SphereGeometry(dataSphere1.radius, dataSphere1.widthSegments, dataSphere1.heightSegments, dataSphere1.phiStart, dataSphere1.phiLength, dataSphere1.thetaStart, dataSphere1.thetaLength);

    sphere1Group.children[0].geometry = newSphereGeometry;
    sphere1Group.children[1].geometry = new THREE.WireframeGeometry(newSphereGeometry);
}

 

 

위의 예제처럼 구 객체에 있는 속성들 컨트롤러로 추가해 보겠습니다.

 

5. 구 객체에 있는 속성들을 별도의 그룹으로 분리하기 위해서 Controls에 Folder(폴더)를 추가합니다.

gui.addFolder(title)
  • title(타이틀) : 폴더의 제목 표시줄에 표시할 이름입니다.

 

예제처럼 동일하게 폴더에 표시할 이름을 "THREE.SphereGeometry"으로 설정합니다.

// 컨트롤러에 구 그룹 객체를 위한 Folder(폴더) 추가
const folder1 = gui.addFolder('THREE.SphereGeometry');

 

6. 객체(dataSphere1)로 컨트롤러에 추가합니다.

  • 각각의 컨트롤러에 $1(최소 값, 선택 값), max(최대 값)은 SphereGeometry(스피어 지오메트리, 구 기하 도형)의 기본값으로 설정합니다.
  • 컨트롤러가 변경될 때마다 구 그룹 지오메트리 변경 함수(updatesShereGroupGeometry)가 호출되도록 설정합니다.
// 컨트롤러 추가
// 구 지오메트리의 파라미터들로 추가
folder1.add(dataSphere1, 'radius', 1, 30).onChange(updatesShereGroupGeometry);
folder1.add(dataSphere1, 'widthSegments', 3, 64).step(1).onChange(updatesShereGroupGeometry);
folder1.add(dataSphere1, 'heightSegments', 2, 32).step(1).onChange(updatesShereGroupGeometry);
folder1.add(dataSphere1, 'phiStart', 0, Math.PI * 2).onChange(updatesShereGroupGeometry);
folder1.add(dataSphere1, 'phiLength', 0, Math.PI * 2).onChange(updatesShereGroupGeometry);
folder1.add(dataSphere1, 'thetaStart', 0, Math.PI * 2).onChange(updatesShereGroupGeometry);
folder1.add(dataSphere1, 'thetaLength', 0, Math.PI * 2).onChange(updatesShereGroupGeometry);

 

다양하게 컨트롤러의 값들을 변경시켜서 구 객체가 변경되는 것을 확인해 보시기 바랍니다.

728x90
반응형