Three.js 성능 개선하기

2025. 6. 8. 15:09·웹/JS

이전에 도서 정보 홈페이지에서 책을 3D로 확인하고 회전해볼 수 있는 기능을 제공하기 위해 Three.js를 활용했었습니다.

 

2024.12.20 - [웹/JS] - three.js로 3D 책 구현하기

 

three.js로 3D 책 구현하기

※ Next.js 14.2.18 버전의 App router와 three.js 0.171.0 버전 사용도서와 관련한 간단한 홈페이지를 구현하게되면 책을 3D로 둘러볼수 있는 기능을 넣어보고 싶었다. 자바스크립트에서는 간편하게 3D 개

cstelladev.tistory.com

 

Three.js는 requestAnimationFrame을 이용해 애니메이션 루프를 만들고 그 루프 안에서 WebGL을 통해 장면을 그려냅니다. 쉽게말해 일정 주기(예: 60 FPS 기준 초당 60번)로 화면에 그림을 그리는 함수를 호출해 애니메이션을 만들어내는 구조입니다.

 

그런데 도서 상세 페이지에 접속해있으면 CPU와 GPU의 이용률이 급격히 상승하고 애니메이션이 동작하지 않을때도 이용률이 낮아지지 않는 현상이 발생했습니다.

 

웹 페이지가 과도하게 시스템 자원을 낭비하면 UI/UX 저하는 물론이고 사용자의 멀티태스킹이나 전체 컴퓨팅 환경에도 부정적인 영향을 미칠 수 있습니다.

 

불필요한 렌더링 과정을 줄여서 성능을 개선해 보겠습니다.

 

 

1. Canvas의 frameloop

Three.js가 3D 객체를 그려낼때는 canvas를 사용합니다. 이때 Canvas의 frameloop 속성값을 따로 지정하지 않으면 기본값인 always로 동작합니다. 애니메이션이 정지해있어서 렌더링을 추가로 할 필요가 없는 상황에도 초당 60프레임의 렌더링 연산을 수행하면 성능 저하가 일어나게됩니다.

 

먼저 canvas의 frameloop 속성을 demand로 수정합니다. demand 옵션을 사용하면 렌더링 연산이 자동으로 이루어지지 않고 렌더링이 필요한 시점에 렌더링 명령을 수동으로 수행해줘야합니다.

<Canvas camera={{ position: [24, 0, 0], fov: 13 }} shadows frameloop="demand">
    <!-- frameloop="demand" 추가 -->
    <ambientLight intensity={0.5} />
    <spotLight
        position={[20, 3, 3]}
        angle={0.2}
        castShadow
        shadow-mapSize-width={512}
        shadow-mapSize-height={512}
        shadow-radius={50}
    />
    <RotatingBook rotationY={rotationY} cover={cover} />
    <Plane />
</Canvas>

 

이전에 구현한 소스코드에서 canvas쪽에 frameloop="demand" 속성을 추가해줬습니다.

 

 

 

2. 수동 렌더링 명령을 위한 invalidate();

frameloop 속성이 demand로 지정된 상태에서 렌더링 명령을 내려줄땐 invalidate()를 사용합니다.

const { invalidate } = useThree();
    
// 애니메이션 시작지점에 invalidate()를 한번 호출
useEffect(() => {
    invalidate();
}, [rotationY]);

useFrame(() => {
    if (bookRef.current) {
        const currentY = bookRef.current.rotation.y;
        const targetY = rotateAngle[rotationY];

        if (Math.abs(currentY - targetY) > 0.001) {
            bookRef.current.rotation.y = THREE.MathUtils.lerp(currentY, targetY, 0.1);
            invalidate();
            // 책의 각도가 변하는 중에만 렌더링 명령 수행
        } else {
            bookRef.current.rotation.y = targetY;
        }
    }
});

 

먼저 애니메이션이 시작될때 렌더링 연산을 한번 호출해줍니다.

 

책을 회전시킬때는 현재 각도와 목표 각도의 차이를 계산하면서 차이가 좁혀질때까지 현재 각도를 조금씩 목표 각도에 가깝게 수정해줍니다. 수정을 반복하다가 목표각도에 충분히 가까워지면 현재각도를 목표각도로 수정하고 애니메이션 루프가 정지합니다.

 

여기서 각도가 수정되는 부분에 invalidate()를 추가했습니다. 현재 각도가 변화하는 부분에서만 렌더링 명령을 호출해서 실제로 3D 객체가 움직일때만 렌더링을 수행하고 움직이지 않을때는 렌더링을 수행하지 않도록 했습니다.

 

 

 

3. 결과

크롬 개발자도구의 Performance 탭에서 개선 결과를 확인해보겠습니다.

성능기록 시작 후 2초지점에 회전, 4초지점에 회전한 뒤 6초지점에 성능기록을 종료했습니다.

 

Main 영역과 Summary 탭을 통해 이벤트 발생 빈도를 확인해 보겠습니다.

수정 전 Main 영역
수정 후 Main 영역
수정 전 Summary
수정 후 Summary

 

전반적으로 Scripting, Painting, Rendering 자체가 줄어들었고 무엇보다 필요한 지점에만 연산이 수행됨을 확인할 수 있습니다.

 

 

 

4. 결론

페이지를 모니터링하며 개발을 진행하던 중 성능 저하가 발생하여 원인을 찾고 개선해보았습니다.

초당 프레임 수 자체를 줄여 연산량을 감소시키는 방법도 있겠지만 부드러운 애니메이션을 제공하는것이 더욱 중요하다 생각되어 프로젝트에 적용해보지는 않았습니다.

불필요한 연산을 줄이는것만으로 상당히 높은 성능 체감 차이를 느낄 수 있었습니다.

 

 

 

 

 

📖 이 글은 학습 과정에서 정리한 내용이라 부족한 점이나 정확하지 않은 부분이 있을 수 있습니다.
😊 읽어주셔서 감사합니다.

'웹 > JS' 카테고리의 다른 글

three.js로 3D 책 구현하기  (1) 2024.12.20
Debounce와 Throttle을 통한 최적화  (0) 2024.12.13
구조 분해 할당  (0) 2024.10.25
배열 내에 참조타입(객체 등)이 있을때 중복 제거하기  (0) 2024.10.15
한국환경공단 대기오염 데이터 활용하기 (parseStringPromise, find, startsWith, padStart)  (0) 2024.10.13
'웹/JS' 카테고리의 다른 글
  • three.js로 3D 책 구현하기
  • Debounce와 Throttle을 통한 최적화
  • 구조 분해 할당
  • 배열 내에 참조타입(객체 등)이 있을때 중복 제거하기
루트노트
루트노트
  • 루트노트
    루트노트
    루트노트
  • 글쓰기 관리
  • 전체
    오늘
    어제
    • 분류 전체보기 (75)
      • 웹 (47)
        • HTML, CSS (11)
        • JS (11)
        • Node.js (3)
        • React (10)
        • Next.js (9)
        • MongoDB (1)
        • Design (2)
      • 애플리케이션 (5)
        • Swift (4)
        • React Native (1)
      • AI (0)
        • 컴퓨터 비전 (영상처리) (0)
      • 임베디드 (4)
        • 아두이노 (0)
        • 라즈베리파이 (0)
        • 젯슨 (1)
        • 리눅스 (3)
      • 컴퓨터 과학 (18)
        • 자료구조 (0)
        • 알고리즘 • 수학 (3)
        • 백준 문제풀이 (4)
        • 프로그래머스 문제풀이 (9)
        • 기타 (2)
      • 개인 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 최근 글

  • 인기 글

  • hELLO· Designed By정상우.v4.10.3
루트노트
Three.js 성능 개선하기
상단으로

티스토리툴바