개요
Three.js를 사용하면서 3D Scene의 파라미터를 실시간을 조정하고 싶은 순간이 있습니다. 조명 세기, 카메라 위치, 메쉬의 회전값, 머터리얼의 컬러 등 에 매우 유용한 도구가 바로 dat.GUI와 lil-gui입니다.
이 글에서는 그 차이와 사용법, 그리고 실제 실무에서 활용할 수 있는 예제들을 하나씩 정리해봅시다.
dat.GUI
dat.GUI는 Three.js 예제에서 오랫동안 사용된 고전적인 UI 컨트롤 라이브러리입니다. 사이드에 뜨는 슬라이더 기반의 컨트롤러를 통해 개발자가 실시간으로 3D 오브젝트 속성값을 조절할 수 있도록 도와줍니다.
const gui = new dat.GUI();
gui.add(light, 'intensity', 0, 2, 0.01); // 라이트 세기 조절
gui.add(mesh.position, 'x', -5, 5); // 메쉬 위치 x값 조절
하지만 단점도 존재합니다:
- UI가 데스크톱 기반으로 고정적
- 모바일 친화적이지 않음
- 유지보수가 사실상 중단
lil-gui
lil-gui는 dat,GUI의 후속으로, Three.js 주요 개발자인 Mr.doob이 직접 만든 경량 UI 라이브러리 입니다. 기존의 dat.GUI를 래핑해 더 가벼운(lighter), 모바일 대응(responsive) 라이브러리입니다. Three.js 공식 예제들도 대부분 lil-gui로 전환된 상태입니다.
import GUI from 'lil-gui';
const gui = new GUI();
gui.add(mesh.position, 'y', -2, 2);
gui.addColor(meterial, 'color'); // 컬러 선택기
코드 크기가 작고 로딩이 빠르기 때문에, 가볍고 빠르며, 데스크톱뿐만 아니라 터치 기반의 모바일 환경에서도 사용하기 위해 반응형 UI로 설계되었으며, 현대적인 디자인으로 개발 도중 테스트나 디자이너의 설정값 조율에도 매우 유용하게 사용됩니다.
사용 방법
- 슬라이더 (Range)
변수를 범위 안에서 조절하고 싶을 때 가장 많이 사용하는 기능입니다.
gui.add(mesh.position, 'y')
.min(-3)
.max(3)
.step(0.01)
.name('elevation');
- .min, .max(): 범위 지정
- .step(): 증감 단위
- .name(): 라벨 이름 변경
let myVariable = 1337
gui.add(myVariable, '???');
단일 변수(let myVar = 1234)는 gui.add()로 바로 조작할 수 없습니다. 반드시 객체로 감싸야 합니다.
const myObject = {
myVariable: 1337
}
gui.add(myObject, 'myVariable');
이를 통해 GUI 패널에서 값을 변경할 수 있습니다.
- 체크박스(Boolean 값)
Boolean 값을 GUI에 연결하면 자동으로 체크박스 형태의 UI가 생성됩니다.
gui.add(mesh, 'visible')
이런식으로 boolean의 값의 코드를 변수로 받으면 체크박스 기능이 활성화됩니다.
gui.add(material, 'wireframe')
material.wireframe도 마찬가지로 on/off 할 수 있습니다.
- 컬러 변경 (Color Picker)
색상을 실시간으로 조절할 수 있는 컬러 피커 기능도 제공합니다. 단, addColor를 사용해야 합니다.
gui.addColor(material, 'color')
addColor를 바로 사용해 적용해 보면 바뀌지않습니다.
addColor만 사용하는 것이 아닌 onChange함수를 이용해서 관리해주어야 합니다.
gui.addColr(material, 'color')
.onChange((value) => {
console.log(value.getHexString())
})
색상이 변경되는 것을 확인할 수 있습니다. 다만 여러 머터리얼의 컬러를 통일하지 못하고, 따로 관리해야합니다. 이러한 부분을 DebugObject처럼 공통 객체를 만들어 사용하는 것이 유지보수에 유리합니다. 특히, 디자이너가 직접 값을 수정해 테스트해보기도 좋습니다.
debugObject.color = '#00ffff'
/* geometry와 mesh는 있다고 가정*/
const material = new.THREE.MeshBasicMaterial({ color: debugObject.color })
gui.addColor(debugObject, 'color')
.onChange((value) => {
material.color.set(debugObject.color)
})
debugColor에 묶인 여러 material의 변수들을 확인하고 체크할 수 있게 된다. 프로젝트가 커질수록 디자이너와 아티스트가 교체하거나 JSON 형태로 세팅값을 보관하기 유리합니다.
- 버튼 (Function)
함수를 버튼처럼 연결해서 사용도 가능합니다.
debugObject.spin = () => {
gsap.to(mesh.rotation, { duration: 1, y: mesh.rotation.y + Math.PI * 2})
}
gui.add(debugObject, 'spin')
클릭 시 spin() 함수가 실행되어 메쉬가 회전합니다. gsap와 함께 쓰면 애니메이션 효과도 자연스럽게 표현할 수 있습니다.
- Geometry 변경
// ❌ 이렇게 하면 안 된다!
// gui.add(geometry, 'widthSegments');
// → geometry는 한 번 생성하면 내부 값을 바로 수정할 수 없기 때문
Three.js의 geometry는 한 번 생성되면 내부 세분화 값을 직접 수정할 수 없습니다. 따라서 슬라이더로 widthSegments 같은 값을 바꾸려면 기존 geometry를 완전히 dispose(폐기) 하고, 새로 생성해야 합니다.
- onFinishChange()
debugObject.subdivision = 2;
cubeTweaks.add(debugObject, 'subdivision')
.min(1)
.max(20)
.step(1)
.onFinishChange(() => {
mesh.geometry.dispose(); // 메모리 해제
mesh.geometry = new THREE.BoxGeometry(
1, 1, 1,
debugObject.subdivision,
debugObject.subdivision,
debugObject.subdivision
);
});
.onFinishChange()는 사용자가 슬라이더 조작을 "마쳤을 때" 단 한번 실행됩니다. 반대로 .onChange()는 슬라이더가 움직이는 중에도 계속 호출되어 CPU 부담이 클 수 있습니다. 이처럼 geometry를 새로 생성해야 하는 작업은 조작 완료 시점에 한 번만 실행되도록 onFinishChange()를 쓰는 게 바람직합니다.
subdivision, segments, resolution처럼 geometry 자체를 바꾸는 값은 항상 dispose()와 함께 새로 만들도록 습관화하는 것이 Three.js 성능 관리에 좋습니다.
lil-gui 옵션 설정 및 토글 기능
const gui = new GUI({
width: 300, // 패널 너비(px)
title: 'Nice debug UI', // 패널 상단 제목
closeFolders: false // 폴더 자동 접힘 방지
});
옵션 설명
- width: GUI 패널의 너비를 설정합니다. 기본값은 auto입니다.
- title: 상단 제목을 지정할 수 있습니다.
- closeFolders: true로 설정하면 폴더들이 기본적으로 접힌 상태 시작합니다. false면 펼쳐집니다.
패널 숨기기 / 보이기
- gui.close(): UI 패널을 닫지만 DOM은 남아있습니다.
- gui.hide(): UI 자체를 숨깁니다. (display: none 처리)
키보드로 GUI 토글
window.addEventListener('keydown', (event) => {
if (event.key === 'h') {
gui.show(gui._hidden);
}
});
- h 키를 누르면 GUI의 표시 여부를 토글합니다.
- gui._hidden은 내부적으로 숨김 상태를 나타내는 비공식 변수지만, 실무에서 간단한 토글 용도로 자주 사용됩니다.
참고 : _hidden은 비공개 프로퍼티이므로 정식 API로는
gui.hide()와 gui.show(true/false) 사용을 권장합니다.
결론
lil-gui는 Three.js 개발에 있어 강력하고도 직관적인 디버그 도구입니다. 디자이너와 개발자가 실시간으로 파라미터를 조정하며 실험할 수 있어 UI 테스트, 시각 튜닝, 최적화에 모두 효과적입니다.
프로젝트가 커질수록 변수들을 객체로 구조화하고, 불필요한 리렌더링을 막기 위해 onFinishChange()를 활용하여 GUI 상태를 토글할 수 있도록 설정해두면 더욱 유지보수성과 협업 효율이 향상됩니다.
lil-gui는 단순히 예제용 UI가 아니라, 실무에서도 충분히 활용 가능한 가볍고 세련된 디버깅/컨트롤 패널입니다. Three.js를 다룬다면 꼭 익혀두면 좋은 도구라고 생각합니다.
'Three.js > Intro' 카테고리의 다른 글
[threejs-journey 1-10] Texture (0) | 2025.06.25 |
---|---|
[threejs-journey 1-8] Geometries (0) | 2025.06.16 |
[threejs-journey 1-7] Resizing & FullScreen (0) | 2025.06.12 |
[threejs-journey 1-6] Control (0) | 2025.06.10 |
[threejs-journey 1-6] Camera (3) | 2025.06.10 |