Skip to content

SVG 돌출 및 가져오기 지원 범위 ​

39강 데모에서 직접 조작할 수 있습니다.

SVG 지원 조건 ​

변환기는 단색 채우기가 하나인 닫힌 윤곽을 받습니다. <path>, <line>, <polyline>, <polygon>, <rect>, <circle>, <ellipse> 위의 단색 SVG 스트로크는 닫힌 편집 가능 Path로 펼쳐집니다.

따라서 스트로크만 있는 열린 선과 패스도 돌출할 수 있습니다. 도형에 채우기와 스트로크가 모두 있으면, 스트로크는 채운 소스 위의 별도 Path가 됩니다.

둘 다 SVG 그룹 변환을 유지하고 GLB로 내보낼 수 있습니다. 둥근 캡과 사각 캡, 그리고 둥근 조인, 베벨 조인, 마이터 조인이 보존됩니다.

SVG의 stroke="none" 자리 표시자는 무시됩니다. 변환기는 evenodd 구멍을 포함한 fill-rule을 보존하고, SVG 그룹에서 페인트와 스트로크 너비를 상속합니다.

그냥 채운 사각형은 편집 가능한 Rect 노드로 남고, 둥근 사각형, 타원, 닫힌 폴리라인은 편집 가능한 Path가 됩니다. 채우기, 스트로크, 불투명도, 채우기 규칙, 스트로크 기하에 대한 인라인 style 선언은 프레젠테이션 속성보다 우선합니다.

fill="currentColor"와 stroke="currentColor"는 도형, 그룹, <use> 인스턴스, SVG 루트 중 가장 가까운 color로 해석됩니다. 색이 없으면 기본값은 검정입니다.

style로 준 스트로크도 펼칠 수 있습니다. 외부 CSS 스타일시트는 파싱하지 않습니다.

돌출에서는 둥근 사각형이 SVG의 독립적인 rx와 ry를 타원형 모서리 호로 보존합니다. 빠진 반지름은 다른 쪽을 기본값으로 하고, 각 반지름은 대응하는 변의 절반으로 제한됩니다.

일반적인 2D Rect 임포터는 여전히 모서리 반지름을 하나만 저장합니다. 해석 가능한 양의 길이 SVG 대시 패턴은 홀수 길이 패턴과 stroke-dashoffset을 포함해, 편집 가능한 별도의 실선 윤곽으로 펼쳐집니다.

길이가 0인 대시에 둥근 캡이 있으면 돌출된 점이 됩니다. non-scaling-stroke는 SVG 그룹 변환과 viewBox 스케일에서도 지정된 너비를 유지합니다.

임포터는 중심선을 먼저 투영한 다음, 편집 가능한 3D 윤곽으로 펼칩니다. 이 너비는 가져올 때 구워지므로, 이후 에디터 줌은 3D 메시를 보통의 공간 물체처럼 확대·축소합니다.

패턴과 그라디언트 ​

클립 패스나 잘린 뷰포트 아래의 스케일되지 않는 스트로크, 길이가 0인 간격, 다른 캡이 있는 길이 0 대시, 그라디언트, 페인트 서버, 지원하지 않는 SVG 도형은 2D로 남습니다. patternUnits="userSpaceOnUse"이고 정수 픽셀 타일이며 기본 SVG 도형을 담은 자체 완결 <pattern> 채우기는 반복되는 2D 채우기로 가져옵니다.

타일 안에서는 로컬 <use>와 선형·방사형 그라디언트, PNG·JPEG·WebP·AVIF 데이터 URL 이미지를 사용할 수 있습니다. 패턴은 로컬 href로 상속할 수 있으며, 숫자 x / y 원점과 patternTransform의 matrix, translate, scale, rotate, skew를 지원합니다. 외부 참조, 외부 이미지, 순환 참조와 그 밖의 페인트 서버는 지원하지 않습니다.

사각형 위의 원형 <radialGradient> 채우기는 userSpaceOnUse를 쓰고, 중심과 반지름이 명시적인 숫자이며, 초점이 중심과 같을 때 2D로 유지됩니다.

타원형 그라디언트, 이동한 초점, 그라디언트 변환을 포함한 그 밖의 자체 완결 방사형 그라디언트는 사각형, 원, 타원, 패스, 폴리곤에 쓸 수 있으며, 래스터화한 SVG 이미지 채우기를 사용합니다. 도형은 계속 편집할 수 있고, 그라디언트 색 정지점은 따로 편집하는 페인트가 아니라 그 이미지 안에 구워집니다.

SVG 이미지 채우기는 확대할 때 텍스처 크기 한도까지 벡터 원본에서 다시 그려지므로, 배율이 높아져도 가장자리가 더 선명하게 남습니다. 스트로크가 유효한 닫힌 메시를 만들지 못하면 원래 2D 노드를 유지합니다.

로컬 참조와 뷰포트 ​

펼친 스트로크 윤곽은 좌표를 정규화하는 동안 소수 여섯 자리를 유지하므로, 아주 얇은 디테일이 최종 메시 검사 전에 납작해지지 않습니다. 지원되는 도형이나 그룹을 가리키는 로컬 <use href="#id">와 레거시 xlink:href는 전방 참조와 반복 참조를 포함해 독립 인스턴스를 만듭니다.

인스턴스의 픽셀 오프셋, 변환, 상속된 채우기는 돌출 전에 적용되고, 각 인스턴스는 자신의 편집 가능한 ID를 받습니다. 순환 참조와 해석되지 않는 참조는 건너뜁니다.

<use>는 viewBox가 있는 <symbol>도 참조할 수 있습니다. 인스턴스나 심볼이 양의 픽셀 width와 height를 제공해야 합니다.

인스턴스 치수가 심볼 치수보다 우선합니다. 심볼의 preserveAspectRatio는 meet 정렬, none, 돌출 윤곽의 slice 클리핑을 지원합니다.

유효 치수가 없거나 잘못되면 그 심볼 인스턴스는 건너뜁니다. 외부 참조는 아직 가져오지 않습니다.

명시적인 양의 픽셀 치수와 viewBox가 있는 중첩 <svg> 요소도 편집 가능한 뷰포트 그룹을 만듭니다. 그 x/y, 변환, preserveAspectRatio는 돌출된 자식에 영향을 줍니다.

로컬 <use>가 이런 SVG 요소 중 하나를 참조하고 뷰포트 치수를 따로 덮어쓸 수 있습니다. 중첩 SVG 뷰포트는 생성된 돌출 윤곽을 기본적으로 자릅니다.

slice도 포함됩니다. 튀어나온 기하를 남기려면 overflow="visible"을 설정하세요.

완전히 안에 있는 도형은 그룹 관계를 유지하므로, 뷰포트 그룹을 움직이면 그 3D 메시도 함께 움직입니다. 가장자리를 가로지르는 도형은 잘린 Path가 됩니다.

클리핑과 가시성 ​

로컬 clip-path="url(#id)"와 인라인 CSS clip-path도 이제 대상이 되는 3D 윤곽을 자릅니다. <clipPath>에는 Path, 폴리곤, 폴리라인, 사각형, 원, 타원, 중첩 그룹, 그리고 그 도형을 가리키는 로컬 <use> 참조가 들어갈 수 있습니다.

그 도형들은 합집합을 이루고, clip-rule="evenodd"는 구멍을 낼 수 있습니다. 그룹과 반복 <use> 인스턴스의 클립은 각자의 변환을 따르고, 여러 조상 클립은 서로, 그리고 SVG 뷰포트와 교차합니다.

clipPathUnits="objectBoundingBox"는 단일 도형의 바운드, 또는 그룹에서 지원되는 자식 도형의 바운드를 변환까지 포함해 사용합니다. 잘린 윤곽은 편집 가능한 Path가 됩니다.

클립 안에 완전히 들어가는 윤곽은 원래 노드와 그룹 관계를 유지합니다. 해석되지 않거나 지원하지 않는 클립 정의는 2D로 남습니다.

마스크, 필터, 클립 패스 안의 텍스트, 외부 클립 참조는 3D로 변환하지 않습니다. display="none"이거나 상속된 visibility="hidden"인 요소는 3D 메시를 만들지 않습니다.

자손은 visibility="visible"을 명시적으로 설정할 수 있습니다. 루트 <svg>를 넘기면 명시적인 픽셀 width/height와 viewBox가 적용됩니다.

preserveAspectRatio도 포함됩니다. 채움 돌출은 중첩 그룹의 SVG skewX, skewY, 전단이 있는 matrix(...) 변환도 보존합니다.

합성 변환에 전단이 있으면 이 윤곽은 샘플링된 선분으로 된 편집 가능한 Path가 됩니다. 일반 viewBox 스케일은 사각형과 곡선 Path를 원래 형태로 편집할 수 있게 유지합니다.

명시적인 픽셀 뷰포트 치수가 없는 SVG는 viewBox 좌표를 유지합니다. 지원하지 않는 2D 도형은 여전히 일반 SVG 임포터를 사용하며, 그 임포터는 원본 전단을 보존하지 않습니다.

preserveAspectRatio="slice"이면 채움 돌출 윤곽이 뷰포트에 맞게 잘립니다. 구멍과, 여러 섬으로 나뉜 도형도 포함됩니다. 뷰포트 안에 완전히 있는 도형은 Rect 또는 곡선 Path 형태를 유지합니다. 지원하지 않는 2D 도형은 여전히 일반 임포터를 따르며, 이 도우미는 그것들을 자르지 않습니다.

데모와 성능 ​

39강 데모에서 Repeated use sample을 고르면, 같은 정의를 서로 다른 채우기로 만든 두 인스턴스와 그 옆의 일반 사각형을 볼 수 있습니다. Symbol viewport sample을 고르면, 구멍이 있는 심볼 하나의 뷰포트 인스턴스 두 개를 비교합니다.

첫 번째는 심볼의 치수를 쓰고, 두 번째는 자신의 치수를 지정합니다. Nested SVG viewport sample을 고르면, 인라인 SVG 뷰포트와 <use>로 참조한 두 번째 인스턴스를 비교합니다.

둘의 돌출 윤곽은 각 뷰포트에 맞게 잘립니다. Paint style + currentColor sample을 고르면, 상속된 색과 인스턴스별 색, 인라인 채우기 덮어쓰기, 스타일이 지정된 스트로크를 비교합니다.

Stroke caps + joins sample을 고르면, 둥근 캡과 사각 캡, 별도의 3D 윤곽이 있는 채운 도형, 그룹 변환 아래의 스케일되지 않는 스트로크, 돌출된 점선 스트로크와 둥근 점을 비교합니다. Clip paths + repeated use sample을 고르면, 구멍이 있고 서로 독립적으로 잘린 두 인스턴스와, 객체 바운드 합집합으로 잘린 도형을 봅니다.

Group bounds + clip use sample을 고르면, 변환된 그룹 위의 객체 바운드 클립을 봅니다. 두 창은 로컬 정의 하나를 재사용합니다.

SVG 사전 검사는 각 윤곽이 메시가 될 수 있는지 확인합니다. 그 CPU 기하는 메시 최대 256개, 기하 배열 합계 8 MiB의 최근 캐시에 남으므로, 비동기 캔버스 업데이트가 3D 동반 메시를 만들 때 재사용할 수 있습니다.

더 오래된 항목은 제거됩니다. GPU 기하는 캔버스마다 별도의 캐시를 갖습니다.

pnpm bench:svg-import:browser를 실행하면 저장소의 Ghostscript Tiger SVG와 다른 대표적인 작품에 대해 가져오기와 편집 시간을 볼 수 있습니다. 그 SVG를 다운로드한 뒤 39강의 Upload SVG로 편집 가능한 레이어를 살펴보고 줌 단계를 비교할 수도 있습니다.

가져온 SVG 레이어가 겹치면, 돌출된 앞면은 중첩 그룹 안의 레이어를 포함해 SVG 페인트 순서를 유지합니다. 연동 3D 뷰에서는 나중에 그린 레이어가 먼저 그린 레이어 위에 보입니다.

겹친 레이어와 GLB ​

GLB 내보내기는 돌출 노드를 같은 앞→뒤 순회 순서로 나열하고, 우리의 glTF 임포터가 그 순서를 유지합니다. 한 평면 위의 불투명하고 평평한 돌출에 대해, 내보내기는 겹치는 레이어를 깊이 방향으로 가장 얇은 돌출 두께의 최대 5%만큼 분리하기도 합니다.

그러면 캔버스의 편집 가능한 도형은 움직이지 않은 채, glTF 뷰어가 서로 다른 깊이 버퍼 값을 갖습니다. 서로 교차하지 않는 스택은 따로 처리하므로, 멀리 있는 3D 메시가 이 간격을 끄지 않습니다.

투영된 바운드가 기울었거나 투명한 돌출, 다른 높이, 또는 독립 3D 메시와 겹치는 스택은 저작된 변환을 유지합니다. 극단적으로 크거나 멀리 있는 모델은 뷰어의 깊이 버퍼 정밀도 때문에 작은 깊이 차이를 잃을 수 있습니다.

Released under the MIT License.