← 과제 목록

[과제] 3주차) ThorVG 활용사례 조사 박성준

@J-unStiN
  • #과제
목차

3주차 과제 블랜더 에 대해서 사례를 조사했습니다. 현재 블랜더는 ThorVG 를 직접적으로 사용하고 있지는 않으나, 기존 사용하던 SVG 엔진(NanoSVG)을 ThorVG 로 전환하려는 움직임이 있어 주제로 선정했습니다.

글의 방향은 아직 실현되지 않은 NanoSVG → ThorVG 전환이 어떻게 일어날지 예측해보는 것입니다.


왜 블랜더에서 전환하려는 지에 대한 간단 요약

  • NanoSVG는 일부 SVG 기능들을 지원하지 않습니다. image
image
  • ThorVG는 SVG Tiny 사양을 거의 완벽하게 지원합니다. 사실, 대부분의 경우 이 정도면 충분합니다. image

왜 전환이 하려는지에 대한 자세한 내용은 해당 링크에서 확인가능합니다.

https://devtalk.blender.org/t/we-should-consider-thorvg-as-replacement-of-nanosvg-for-5-1/41565


전환 시나리오를 예상해보기

graph TD
    subgraph PATTERN_A["패턴 A: 파싱 + 래스터라이징 (4개 파일)"]
        A1["blf_glyph.cc — UI 아이콘"]
        A2["format_svg.cc — 파일 썸네일"]
        A3["wm_window_icon.cc — 앱 아이콘"]
        A4["wm_cursors.cc — 마우스 커서"]
    end

    subgraph PATTERN_B["패턴 B: 파싱 + 벡터 추출 (1개 파일)"]
        B1["grease_pencil_io_import_svg.cc<br/>SVG → Grease Pencil"]
    end

    subgraph UNRELATED["NanoSVG 미사용 (1개 파일)"]
        C1["grease_pencil_io_export_svg.cc<br/>pugixml 기반"]
    end

    NANOSVG["NanoSVG"]
    A1 --> NANOSVG
    A2 --> NANOSVG
    A3 --> NANOSVG
    A4 --> NANOSVG
    B1 --> NANOSVG

    style PATTERN_A fill:#2ecc7120,stroke:#27ae60
    style PATTERN_B fill:#e74c3c20,stroke:#c0392b
    style UNRELATED fill:#95a5a620,stroke:#7f8c8d

빌드 시스템에는 이미 ThorVG가 준비되어 있습니다

versions.cmakethorvg.cmake 파일을 보면, ThorVG v1.0.3이 외부 빌드 의존성으로 등록되어 있습니다. 다만 아직 source/blender/ 내 어떤 코드에서도 #include <thorvg.h>는 사용되지 않고 있습니다.

image image

패턴 A: 래스터라이징 — 🟡 비슷하지만 주의할 점이 있다

패턴 A는 “SVG를 파싱해서 비트맵 이미지로 변환”하는 흐름입니다. 4개 파일 모두 같은 패턴입니다:

// 현재: NanoSVG — 5줄이면 끝
NSVGimage *image = nsvgParseFromFile(filepath, "px", 96.0f);
NSVGrasterizer *rast = nsvgCreateRasterizer();
nsvgRasterize(rast, image, 0, 0, scale, pixels, w, h, w * 4);
nsvgDeleteRasterizer(rast);
nsvgDelete(image);

ThorVG에서도 비슷한 흐름으로 할 수 있습니다:

// 예상: ThorVG
auto* picture = tvg::Picture::gen();
picture->load(filepath);
picture->size(float(dest_w), float(dest_h));

auto* canvas = tvg::SwCanvas::gen();
canvas->target(buffer, dest_w, dest_w, dest_h, tvg::ColorSpace::ABGR8888S);
canvas->add(picture);
canvas->draw(true);
canvas->sync();

API 흐름 자체는 비슷하지만, 한 가지 주의할 점이 있습니다:

색상 바이트 순서가 다릅니다.

  • NanoSVG 출력: [R, G, B, A] 순서
  • ThorVG 출력: [A, B, G, R] 순서 (ThorVG는 RGBA 옵션을 제공하지 않습니다)

Blender의 아이콘 렌더링, 커서, 썸네일 코드가 모두 RGBA 순서를 가정하고 있기 때문에, ThorVG로 렌더링한 후 바이트 순서를 뒤집어주는 변환 코드가 추가로 필요합니다.


패턴 B: Grease Pencil 임포트 — 🔴 가장 어려운 부분

패턴 A는 SVG를 “그림”으로만 사용합니다 — 픽셀 이미지로 변환하면 끝입니다.

하지만 패턴 B는 다릅니다. SVG 파일 안의 선과 도형 데이터를 직접 읽어서 Blender의 Grease Pencil 오브젝트로 변환합니다. 이 과정에서 NanoSVG의 내부 구조체에 깊이 의존하고 있어, 전환 시 로직을 새로 작성해야 합니다.

어려운 이유 3가지:

1) 레이어 구분 — NanoSVG에 Blender가 직접 패치한 id_parent 필드로 SVG 그룹을 레이어로 매핑합니다. ThorVG에서는 Accessor API를 통해 트리를 순회하는 방식으로 바뀌어야 합니다.

2) 경로 데이터 형식 차이 — NanoSVG는 모든 도형을 큐빅 베지어 포인트 배열로 변환해주지만, ThorVG는 MoveTo/LineTo/CubicTo/Close 같은 명령어 시퀀스로 제공합니다. 이걸 Blender의 베지어 커브로 변환하는 로직을 새로 만들어야 합니다.

3) 색상/선 속성 — NanoSVG의 C 스타일 구조체 접근에서 ThorVG의 C++ API(shape->fill(), shape->strokeFill())로의 매핑이 필요합니다.

마무리

전환이 완료된다면 Blender는 <style>, <mask>, <text> 등 현대 SVG의 풍부한 기능을 제대로 활용할 수 있게 될 것으로 예상됩니다. 유지보수가 멈춘 라이브러리에 자체 패치를 유지하는 기술 부채에서도 벗어나게 됩니다.

감사합니다.

댓글

Discussion 원문