Three.js를 사용해 다중 객체 계층 구조를 관리하던 중, 복잡한 계층 구조가 렌더링 성능에 영향을 미치는 문제가 발생했습니다.
특히, Object3D의 하위 객체들이 많아질수록 getWorldPosition() 메서드를 호출할 때 성능이 급격히 저하되었습니다.
렌더링 속도 저하: 하위 계층 객체가 많을수록 getWorldPosition() 및 기타 World 관련 메서드 호출 시간이 증가했습니다.
프레임 드랍: 애니메이션 루프에서 매 프레임마다 World Position을 계산하면서 FPS가 60에서 30 이하로 떨어지는 현상이 발생했습니다.
병목 지점 확인: 성능 분석 도구를 통해 getWorldPosition() 호출이 병목 지점임을 확인했습니다.
캐싱 도입: World Position 계산 결과를 캐싱하여 중복 계산을 방지.
업데이트 이벤트 최적화: Object3D의 변환이 변경될 때만 캐시를 업데이트하도록 설계.
로컬 데이터를 활용: 모든 하위 객체의 World 데이터를 계산하지 않고 로컬 데이터를 활용해 상대적인 위치를 기반으로 계산.
import * as THREE from 'three';
class OptimizedObject3D extends THREE.Object3D {
constructor() {
super();
this.cachedWorldPosition = new THREE.Vector3();
this.needsWorldUpdate = true;
}
getWorldPosition(target) {
if (this.needsWorldUpdate) {
super.getWorldPosition(this.cachedWorldPosition);
this.needsWorldUpdate = false;
}
return target.copy(this.cachedWorldPosition);
}
updateMatrixWorld(force) {
super.updateMatrixWorld(force);
this.needsWorldUpdate = true;
}
}
최적화된 코드는 다음과 같은 프로젝트에 적용되었습니다.
대규모 3D 데이터 시각화: 3D 모델의 계층 구조를 가진 도시 시뮬레이션 프로젝트에서 FPS가 45에서 60으로 개선되었습니다.
실시간 3D 게임: 여러 계층의 캐릭터와 환경 객체가 존재하는 게임에서 성능이 크게 향상되었습니다.
1. World Position 호출 시간 비교
2. FPS 개선 그래프
Object3D 계층 구조가 복잡한 경우, 불필요한 World Position 계산은 성능 저하를 초래합니다.
이번 최적화를 통해 캐싱과 조건부 업데이트만으로도 큰 성능 개선을 이룰 수 있음을 확인했습니다.
이 방법은 Three.js뿐 아니라 다른 3D 라이브러리에서도 유사한 병목 문제를 해결하는 데 응용할 수 있습니다.
출처: Object 3D