EDITORCLASSBLOGLOGINimg default descriptionimg default descriptionimg default description표현한다는 것의무한한 가능성,새로운 형태로
담아내다.
img default descriptionimg default descriptionimg default descriptionimg default descriptionimg default descriptionimg default descriptionimg default description새로운 형태의 콘텐츠Opkle은 코드 없이 웹을 마음껏 만들고, 누구나 자기 화면을 그릴 수 있도록 에디터를 만들고, 그 결과물을 어디서나 즐길 수 있게 돕는 팀입니다.텍스트와 화면과의 조화를 통해, 웹을 짓는다는 것이 그저 단순한 코딩이 아닌, 상상을 펼치고 감각을 깨우는 과정이 될 수 있도록 좋은 도구를 만들어 냅니다.
옵클 에디터 개발기: 그래픽 엔진 안의 선형대수dev12옵클 에디터 개발기: 인디자인처럼 편집하는 레이아웃 편집기dev13옵클 에디터 개발기: 원고가 다음 페이지로 흐르는 편집기dev14옵클 에디터 개발기: EPUB과 IDML을 편집 가능한 페이지로dev15옵클 에디터 개발기: 한 번 만든 레이아웃을 EPUB과 인쇄물로dev1689101112...12 옵클 에디터 개발기: 그래픽 엔진 안의 선형대수11편에서 Rust 공장을 그래픽 엔진으로 다듬는 과정을 정리했다면, 그 다음에 더 깊게 들어가야 할 부분은 선형대수였습니다. 그래픽 에디터에서 이미지 레이어를 움직이고, 회전시키고, 찌그러뜨리고, 네 꼭짓점에 맞춰 원근을 바꾸고, 픽셀을 다시 샘플링하고, 래스터 이미지를 벡터 path로 바꾸는 일은 겉으로는 모두 다른 기능처럼 보입니다. 하지만 엔진 안에서는 거의 같은 언어로 설명됩니다. 벡터, 행렬, 기저, 좌표계, 사영공간, 보간, 최소제곱, 정규화, 고유한 수치 안정성의 문제입니다.그래서 그래픽 에디터를 제대로 만들려면 수학을 UI 뒤편에 숨길 수는 있어도, 엔진 안에서 피할 수는 없습니다. 사용자는 handle을 드래그할 뿐이지만, Rust core는 그 드래그를 좌표 변환으로 해석해야 합니다. 사용자는 이미지를 기울일 뿐이지만, 내부에서는 3×3 homography가 만들어지고, 역행렬이 계산되고, output pixel마다 source coordinate가 다시 계산됩니다. 사용자는 SVG로 바꾸기 버튼을 누를 뿐이지만, 내부에서는 픽셀 격자의 연결 성분, 경계 추적, 곡선 근사, path precision의 균형이 움직입니다.이 글은 그래서 11편의 후속이지만, 조금 더 수학 쪽으로 내려간 기록입니다. 핵심 설계를 전부 펼쳐놓는 글은 아니고, 그래픽 엔진을 만들 때 실제로 어떤 수학적 판단이 필요했는지에 대한 개발 일지에 가깝습니다. 옵클 그래픽 에디터는 단순한 캔버스 UI가 아니라, 좌표와 픽셀과 벡터가 서로 오갈 수 있는 편집 엔진이어야 했습니다.Vector space그래픽 엔진에서 가장 먼저 정리해야 하는 것은 모든 데이터가 결국 벡터라는 사실이었습니다. 한 픽셀의 RGB는 3차원 벡터이고, RGBA는 4차원 벡터입니다. 한 점의 위치는 2차원 벡터이고, affine transform을 위해 동차좌표로 올리면 3차원 벡터가 됩니다. 색 보정의 channel vector, 브러시의 방향 벡터, path segment의 control point, PDF page 위의 좌표까지 모두 어떤 vector space 안의 원소로 볼 수 있습니다.이 관점을 잡으면 코드의 감각도 달라집니다. 픽셀 하나를 바꾸는 일은 단순히 숫자 네 개를 고치는 일이 아니라, `R^4` 안의 벡터를 다른 벡터로 보내는 함수입니다. 이미지 전체는 `Z²` 격자 위에 놓인 벡터장처럼 볼 수 있습니다. 브러시 stroke는 특정 영역 안의 벡터장을 다른 벡터장과 섞는 연산이고, 블러는 각 위치의 벡터를 주변 벡터들의 가중합으로 바꾸는 선형 연산에 가깝습니다.여기서 선형성은 매우 중요합니다. 어떤 연산 T가 `T(a x + b y) = a T(x) + b T(y)`를 만족하면, 그 연산은 합성과 분해가 쉬워집니다. 블러 같은 convolution은 이상적인 조건에서는 선형 연산입니다. 이미지 A와 이미지 B를 더한 뒤 블러를 거는 것과, 각각 블러를 건 뒤 더하는 것이 같은 구조를 갖습니다. 물론 실제 엔진에서는 clamp, gamma, alpha, integer quantization 때문에 완전한 선형성은 깨집니다. 그래도 내부 사고의 출발점은 선형 연산으로 잡는 편이 훨씬 안정적입니다.반대로 HSL 변환, gamma 보정, thresholding, clamp 같은 작업은 비선형입니다. 이 비선형 연산들은 사용자가 보기에는 자연스럽지만, 합성 순서에 민감합니다. blur를 먼저 하고 threshold를 하는 것과 threshold를 먼저 하고 blur를 하는 것은 완전히 다른 결과를 만듭니다. 그래서 그래픽 엔진에서는 어떤 처리가 선형이고 어떤 처리가 비선형인지, 어떤 순서로 묶어야 시각적으로 납득 가능한지 계속 구분해야 했습니다.Coordinate frame그래픽 에디터에서 좌표계는 하나가 아닙니다. 화면 좌표가 있고, 캔버스 좌표가 있고, 레이어 내부 좌표가 있고, 이미지 픽셀 좌표가 있고, export용 페이지 좌표가 있습니다. 사용자가 마우스로 잡은 점은 screen space에 있지만, 실제로 바뀌어야 하는 것은 layer local space의 geometry일 수 있습니다. 이 좌표계를 명확히 구분하지 않으면 에디터는 금방 이상해집니다.선형대수적으로는 각 좌표계를 basis가 다른 vector space처럼 생각할 수 있습니다. 같은 점 p라도 어떤 basis에서 보느냐에 따라 좌표값이 달라집니다. 캔버스가 확대되어 있거나, 스크롤되어 있거나, 레이어가 회전되어 있으면 마우스 좌표를 그대로 이미지 픽셀 좌표로 쓸 수 없습니다. 변환 행렬을 거꾸로 따라가며 screen point를 document point로, 다시 layer-local point로 내려야 합니다.이때 affine transform은 3×3 행렬로 통일하는 것이 좋습니다. 2차원 좌표 `(x, y)`를 동차좌표 `(x, y, 1)`로 올리면 translation, rotation, scale, shear를 모두 하나의 행렬 곱으로 표현할 수 있습니다. 예를 들어 이동은 마지막 열에 들어가고, 회전과 확대는 좌상단 2×2 block 안에 들어갑니다. 이렇게 하면 여러 변환을 순서대로 적용할 때 행렬 곱으로 합성할 수 있습니다.중요한 것은 행렬 곱의 순서입니다. `ABp`는 p에 먼저 B를 적용하고 그 다음 A를 적용한다는 뜻입니다. 사용자가 보기에는 “이동하고 회전했다”와 “회전하고 이동했다”가 비슷해 보일 수 있지만, 실제 결과는 다릅니다. 특히 레이어 중심을 기준으로 회전하려면 원점으로 옮기고, 회전하고, 다시 되돌리는 세 행렬이 필요합니다. 이런 좌표계의 순서를 엔진에서 명확히 잡아두어야 UI의 handle 움직임이 사용자의 기대와 맞습니다.Affine layer그래픽 에디터의 기본 레이어 조작은 대부분 affine transform입니다. 이동, 회전, 확대/축소, 기울이기는 모두 직선을 직선으로 보내고, 평행선을 평행선으로 유지합니다. 이 조건이 유지되는 동안에는 레이어의 bounding box와 handle 계산도 비교적 명확합니다. 직사각형은 평행사변형이 되고, 내부의 비율은 유지됩니다.수식으로 보면 affine transform은 `p' = A p + t`입니다. 여기서 A는 2×2 행렬이고, t는 translation vector입니다. A의 determinant는 면적 scale과 방향성을 알려줍니다. determinant가 0에 가까워지면 변환이 퇴화합니다. 이미지가 한 줄처럼 눌리거나, 역행렬을 구하기 어려워집니다. 그래서 그래픽 엔진에서는 scale이 너무 작아지는 상황, determinant가 지나치게 작아지는 상황을 경계해야 합니다.2×2 행렬 A는 여러 의미를 품고 있습니다. 순수 회전 행렬은 두 basis vector의 길이를 유지하고 서로 직교합니다. scale은 basis vector의 길이를 바꿉니다. shear는 basis vector 사이의 각도를 바꿉니다. 사용자가 UI에서 보기에 “조금 비틀었다”는 동작은 내부적으로 basis vector의 방향과 길이를 바꾸는 일입니다. 그래픽 에디터의 transform panel은 결국 basis를 조작하는 도구입니다.이 구조를 정확히 잡아두면 undo/redo와 export도 안정적입니다. 화면에 보이는 픽셀을 매번 덮어쓰는 방식이 아니라, 원본 자산과 transform matrix를 분리해 보관할 수 있습니다. 사용자는 여러 번 회전하고 확대할 수 있지만, 내부에서는 가능한 한 원본과 변환 정보를 유지하다가 필요한 시점에 rasterize합니다. 그래야 반복 편집으로 인한 품질 손실을 줄일 수 있습니다.Projective geometry그런데 그래픽 에디터가 affine transform만 다루면 표현이 금방 막힙니다. 포스터를 벽에 붙인 것처럼 보이게 하거나, 비스듬히 촬영된 이미지를 펴거나, 네 꼭짓점을 마음대로 잡아 이미지 레이어를 맞추려면 사영 변환이 필요합니다. 이때부터는 평행선이 더 이상 평행선으로 남지 않아도 됩니다. affine geometry에서 projective geometry로 넘어가는 순간입니다.사영 변환은 동차좌표에서 3×3 행렬 H로 표현됩니다. 2차원 점 `(x, y)`를 `(x, y, 1)`로 올리고, `H[x, y, 1]^T`를 계산한 뒤, 마지막 성분 w로 나누어 다시 `(x'/w, y'/w)`를 얻습니다. 여기서 w가 들어가는 순간이 중요합니다. affine transform에서는 마지막 성분이 항상 1처럼 유지되지만, projective transform에서는 위치에 따라 w가 달라집니다. 그 결과 멀어지는 방향으로 축소되는 원근감이 생깁니다.사영공간에서는 `(x, y, w)`와 `(λx, λy, λw)`가 같은 점을 나타냅니다. 좌표가 하나의 대표값이 아니라 비율로 정의됩니다. 이 관점은 처음에는 낯설지만, 원근 변환을 다룰 때 굉장히 편합니다. 무한원점도 표현할 수 있고, 평행선의 소실점도 같은 수학 안으로 들어옵니다. 그래픽 에디터에서 네 꼭짓점 transform이 자연스럽게 보이려면 이 projective space를 엔진이 정확히 다뤄야 합니다.4점 대응으로 homography를 구할 수 있는 이유도 여기에 있습니다. 하나의 3×3 행렬에는 scale을 제외하고 8개의 자유도가 있습니다. 사각형의 네 점을 다른 네 점으로 보내는 조건은 각 점마다 x, y 두 개의 제약을 주므로 총 8개의 제약이 됩니다. 그래서 일반적인 위치의 네 점 대응은 하나의 homography를 결정합니다. 사용자가 네 모서리 handle을 움직이는 행위가 정확히 이 8자유도 변환을 지정하는 셈입니다.DLT와 정규화homography를 구할 때는 대응점에서 선형 방정식을 세웁니다. source point `p = (x, y, 1)`와 target point `p' = (u, v, 1)`가 있을 때, `p' × H p = 0`이라는 관계를 만들 수 있습니다. cross product가 0이라는 것은 두 동차좌표 벡터가 같은 방향, 즉 같은 projective point를 가리킨다는 뜻입니다. 이 식을 정리하면 H의 원소들에 대한 선형 방정식 두 개가 나옵니다.네 점 대응이면 이런 방정식이 여덟 개 쌓입니다. H는 scale까지 포함하면 아홉 원소지만, 동차좌표에서는 전체 scale이 의미 없기 때문에 자유도는 여덟 개입니다. 그래서 마지막 원소를 1로 고정하거나, 전체 벡터의 norm을 기준으로 정규화해 해를 잡을 수 있습니다. 더 일반적으로는 행렬 A를 만들고 `Ah = 0` 형태의 homogeneous least squares 문제로 풀 수 있습니다.여기서 수치 안정성이 중요합니다. 좌표값이 너무 크거나, 네 점이 한쪽에 몰려 있거나, 거의 일직선에 가까우면 방정식의 condition이 나빠집니다. 작은 floating point 오차가 H의 계수에 크게 증폭될 수 있습니다. 그래서 Hartley normalization을 거칩니다. 각 점 집합의 centroid를 원점으로 옮기고, 평균 거리가 `sqrt(2)` 정도가 되도록 scale을 맞춥니다. 그런 다음 normalized coordinate에서 homography를 구하고, 마지막에 다시 원래 좌표계로 되돌립니다.이 정규화는 단순한 전처리처럼 보이지만 결과 품질에 꽤 큰 영향을 줍니다. 같은 네 점을 넣어도 좌표계가 안정적이면 행렬 계산이 덜 흔들립니다. 그래픽 에디터에서는 사용자가 아주 작은 레이어를 다루거나, 아주 큰 캔버스에서 작업하거나, 모서리를 거의 한 줄로 눌러버리는 상황이 생길 수 있습니다. 그런 상황에서도 엔진은 가능한 한 예측 가능한 결과를 만들어야 합니다.내부적으로 모든 세부 공식을 UI에 드러낼 필요는 없습니다. 사용자는 네 꼭짓점을 잡고 움직일 뿐입니다. 하지만 Rust 공장 안에서는 그 네 점이 선형 방정식이 되고, 그 방정식이 행렬로 쌓이고, 그 행렬의 안정성이 검사되고, 그 결과가 다시 pixel sampling으로 이어집니다. 이 체인이 흔들리지 않아야 원근 도구가 실제 도구처럼 느껴집니다.Inverse mapping원근 변환 행렬을 얻었다고 해서 작업이 끝나는 것은 아닙니다. 실제 이미지를 만들어야 합니다. 여기서 중요한 선택이 forward mapping과 inverse mapping입니다. forward mapping은 source pixel을 target 위치로 보내는 방식입니다. 직관적이지만 문제가 있습니다. target image의 어떤 픽셀은 아무 source pixel도 받지 못해 hole이 생길 수 있습니다. 특히 확대나 원근 변형이 들어가면 빈 픽셀이 더 잘 생깁니다.그래서 렌더링은 inverse mapping으로 잡는 편이 안정적입니다. output image의 각 픽셀 중심 `(u, v)`를 순회하면서, 역행렬 `H^-1`을 이용해 source image의 어느 좌표 `(x, y)`에서 왔는지를 찾습니다. output 격자를 빠짐없이 순회하기 때문에 hole이 생기지 않습니다. source 좌표가 이미지 밖이면 투명 픽셀로 처리하고, source 안쪽이면 sampling을 합니다.이때 source coordinate는 보통 정수 좌표에 딱 떨어지지 않습니다. `(12.37, 45.82)` 같은 실수 좌표가 나옵니다. 그래서 nearest neighbor로 가장 가까운 픽셀을 고르면 계단 현상이 생깁니다. bilinear interpolation을 쓰면 주변 네 픽셀을 x, y 방향의 소수부에 따라 가중 평균합니다. x 방향 소수부를 tx, y 방향 소수부를 ty라고 하면 네 픽셀의 weight는 `(1 - tx)(1 - ty)`, `tx(1 - ty)`, `(1 - tx)ty`, `tx ty`가 됩니다.이 보간은 작은 수학이지만 품질 차이를 크게 만듭니다. 특히 텍스트가 들어간 이미지나 경계가 뚜렷한 그래픽에서 nearest neighbor는 거칠고, bilinear는 훨씬 자연스럽습니다. 더 높은 차수의 보간도 생각할 수 있지만, WASM에서 반복 호출되는 편집 엔진에서는 비용과 품질의 균형이 중요합니다. 실시간 조작에서는 bilinear가 꽤 좋은 기본점이 됩니다.알파가 들어오면 이야기가 더 예민해집니다. straight RGBA를 그대로 보간하면 투명 픽셀의 RGB가 결과에 섞여 fringe가 생깁니다. 그래서 premultiplied alpha 공간에서 보간하고 다시 straight alpha로 되돌리는 방식이 필요합니다. 수식으로는 먼저 `(r, g, b, a)`를 `(ar, ag, ab, a)`로 보내고, 네 픽셀을 가중합한 뒤, a가 0보다 크면 다시 `(ar/a, ag/a, ab/a, a)`로 복원합니다. 이 작은 차이가 원근 변환의 가장자리 품질을 만듭니다.Singular value와 조건수그래픽 변환을 이해할 때 고유값보다 더 직접적인 도구는 singular value decomposition이었습니다. 임의의 행렬 A는 `A = UΣVᵀ`로 분해할 수 있습니다. V의 열벡터는 입력 공간의 직교 방향이고, Σ의 대각 원소는 각 방향이 얼마나 늘어나는지 나타내며, U는 늘어난 축이 출력 공간에서 향하는 방향을 나타냅니다. 회전과 비균일 확대, 반사를 한꺼번에 가진 변환도 이 분해 안에서는 기하학적으로 읽을 수 있습니다.2×2 affine matrix에서 가장 큰 singular value를 `σ_max`, 가장 작은 값을 `σ_min`이라고 하면 조건수는 `κ(A) = σ_max / σ_min`입니다. 두 값이 비슷하면 원형이 비슷한 비율의 타원으로 바뀌지만, 비율이 매우 크면 한 방향은 크게 늘고 다른 방향은 거의 선으로 눌립니다. `σ_min`이 0에 가까워질수록 역변환은 입력 오차를 크게 증폭시키고, 정확한 좌표 하나를 구하는 문제가 아니라 잡음과 반올림을 얼마나 확대할 것인지의 문제가 됩니다.sampling 관점에서도 singular value는 중요합니다. 출력 한 픽셀이 원본 공간에서 차지하는 footprint는 변환의 역행렬로 결정됩니다. 한 방향으로 크게 축소되는 구간에서는 원본의 넓은 영역을 하나의 픽셀로 모아야 하므로 저역통과 필터가 필요하고, 반대로 확대되는 구간에서는 없는 세부를 보간해야 합니다. 비등방 변환에서는 두 축의 scale이 다르기 때문에 하나의 전역 해상도만으로 aliasing과 blur를 동시에 막을 수 없습니다.projective transform에서는 이 분석을 위치마다 다시 해야 합니다. homography는 전역적으로 선형이 아니지만 한 점 근처에서는 Jacobian으로 선형화할 수 있습니다. 출력 위치 `(u, v)`에서 Jacobian `J(u, v)`의 singular value를 구하면 그 주변이 원본에서 어느 방향으로 얼마나 확대되거나 압축되는지 알 수 있습니다. 즉 원근 변환의 품질은 행렬 H 하나의 scale이 아니라 공간 전체에 분포한 local condition의 문제입니다.모든 픽셀에서 완전한 비등방 필터를 계산할 필요는 없지만, 조건수와 local Jacobian을 알면 수치적으로 위험한 변환을 판별할 수 있습니다. 거의 일직선이 된 사각형, 지나치게 큰 확대와 역행렬 오차는 모두 같은 언어로 설명됩니다. 자유로운 기하 조작을 허용하면서도 계산이 의미를 잃는 경계를 정하는 데 선형대수는 직접적인 기준이 되었습니다.Tracing math픽셀을 SVG로 바꾸는 작업도 선형대수와 떨어져 있지 않습니다. 래스터 이미지는 격자 위의 sample이고, SVG path는 연속 평면 위의 곡선입니다. tracing은 이산 데이터에서 연속적인 geometry를 복원하는 문제입니다. 완벽한 복원은 불가능합니다. 대신 사람이 보기에 충분히 같은 형태를 갖도록 경계를 찾고, 그 경계를 적절한 path로 근사합니다.binary tracing에서는 먼저 grayscale 값을 만들고 threshold를 정합니다. Otsu threshold는 픽셀들을 두 class로 나누었을 때 class 간 분산이 최대가 되는 임계값을 찾습니다. 수학적으로는 histogram 위에서 `σ_b²(t) = ω0(t)ω1(t)(μ0(t)-μ1(t))²`가 커지는 t를 찾는 문제입니다. 흑백으로 잘 나뉘는 이미지라면 이 값이 좋은 분리점을 줍니다.그 다음에는 연결 성분과 경계를 봅니다. 픽셀 격자에서 같은 class에 속한 영역을 찾고, 그 영역의 boundary를 따라갑니다. 여기서 boundary는 본질적으로 계단 모양입니다. SVG path는 그 계단을 그대로 옮기는 것이 아니라, 직선 segment나 곡선 segment로 근사합니다. 너무 정밀하면 path가 지나치게 많아지고, 너무 단순하면 원래 형태가 망가집니다. path precision은 결국 근사 오차와 데이터 크기 사이의 trade-off입니다.color tracing은 더 복잡합니다. 색 공간 안에서 비슷한 색을 묶고, 각 색상 영역의 경계를 따로 추출해야 합니다. 색상은 RGB cube 안의 점이고, 비슷함은 어떤 metric을 쓰느냐에 따라 달라집니다. 사람이 보기에 가까운 색과 RGB 유클리드 거리에서 가까운 색이 항상 같지는 않습니다. 그래서 그래픽 엔진에서는 모든 수학을 이상적인 형태로만 다루기보다, 실제 제작물에서 안정적으로 보이는 쪽을 선택해야 합니다.output SVG를 반응형 자산으로 쓰기 좋게 만들기 위해 viewBox와 width/height 처리도 정리했습니다. viewBox는 SVG 내부 좌표계의 basis와 범위를 정의합니다. width와 height를 고정 픽셀값으로 박아버리면 EPUB이나 웹 문서 안에서 쓰기 불편해질 수 있습니다. 그래서 geometry의 내부 좌표계는 유지하되, 외부 배치는 유연하게 가져갈 수 있도록 후처리했습니다.Page space페이지 출력에서도 좌표계는 계속 중요했습니다. 화면의 CSS pixel은 물리 길이가 아니라 기준 해상도에 대한 논리 단위이고, device pixel은 실제 래스터 표본이며, 인쇄 문서는 point나 millimeter처럼 물리량과 연결된 단위를 사용합니다. 숫자 100 하나만 저장해서는 그것이 화면의 길이인지 출력물의 길이인지 알 수 없습니다. 좌표에는 언제나 단위와 기준 공간이 함께 있어야 합니다.이 문제는 차원 해석으로 정리할 수 있습니다. 길이 L을 인쇄 점으로 표현하고 해상도를 D pixel/inch라고 하면 래스터 표본 수는 `N = L × D / 72`처럼 계산됩니다. 여기서 L은 point, 72는 point/inch이므로 단위가 소거되고 N만 pixel로 남습니다. 화면 zoom은 이 물리 변환에 들어가면 안 됩니다. zoom은 관찰자의 배율이고 문서 자체의 크기가 아니기 때문입니다.페이지 안에 이미지를 배치하는 contain과 cover도 같은 닮음 변환입니다. 원본 크기를 `(wi, hi)`, 목표 상자를 `(wb, hb)`라고 할 때 contain의 scale은 `min(wb/wi, hb/hi)`, cover의 scale은 `max(wb/wi, hb/hi)`입니다. 남는 차이를 절반씩 translation하면 중앙 정렬이 됩니다. 단순한 공식이지만 어느 좌표가 재단 영역이고 어느 좌표가 실제 콘텐츠 영역인지 먼저 분리하지 않으면 올바른 비율도 잘못된 상자에 적용됩니다.도련과 재단선, 페이지 밖의 인쇄 표식도 모두 같은 page space의 geometry입니다. 콘텐츠 상자와 재단 상자, 도련 상자는 서로 다른 포함 관계를 가지며, 출력 장치에 전달되는 최종 page box는 이 집합들을 모두 품어야 합니다. 반응형 화면에서는 뷰포트가 문서를 바꾸지만 인쇄에서는 문서가 좌표계를 먼저 정의하고 출력 장치가 그 좌표를 표본화합니다.폰트도 이 좌표계에 연결됩니다. 글자는 단순한 문자열이 아니라 glyph outline과 advance, kerning과 baseline metric으로 배치됩니다. 화면과 출력에서 같은 font size를 지정했어도 실제 글꼴이 달라지면 line break와 페이지 수가 바뀝니다. 그래픽 엔진이 실제 제작 도구가 되려면 화면의 수학뿐 아니라 좌표, 글리프와 물리 단위가 파일 안에서 같은 의미로 보존되어야 했습니다.숨겨진 공장이 선형대수 계층을 만들면서 계속 생각한 것은 수학을 사용자에게 보이지 않게 만드는 일이었습니다. 사용자는 determinant를 보지 않습니다. 사용자는 homography의 condition number를 보지 않습니다. 사용자는 bilinear weight를 보지 않습니다. 하지만 그 값들이 안정적으로 계산되지 않으면 사용자는 바로 이상함을 느낍니다. handle이 흔들리고, 이미지 가장자리가 더러워지고, export된 결과가 미묘하게 어긋납니다.그래서 Rust 공장 안에서는 좌표계와 행렬, sampling을 최대한 엄격하게 다뤘습니다. 차원이 맞지 않는 입력, 거의 특이한 행렬, 정의역 밖의 역매핑과 알파 표현의 혼용은 모두 서로 다른 실패 조건입니다. 이를 하나의 막연한 이미지 오류로 처리하지 않고 각 수학적 계약의 위반으로 구분했습니다. 구현의 세부를 밖으로 드러낼 필요는 없지만 내부 계산이 어떤 불변식을 지켜야 하는지는 분명해야 했습니다.이 단계도 완성되었습니다. 원근 변환과 벡터화, 래스터 표본화와 페이지 조립은 단순한 기능 목록이 아니라 하나의 수학적 처리 흐름으로 정리되었습니다. 선형대수와 사영기하, singular value와 조건수, 이산 픽셀과 연속 곡선, 색상 벡터와 물리 단위가 그래픽 공장 안에서 안정적으로 맞물렸습니다. 반복 검수에서도 극단적인 좌표, 퇴화에 가까운 변환, 다양한 종횡비와 출력 해상도에서 결과가 일관되게 유지되었고, 옵클 그래픽 에디터는 UI 뒤편에 제대로 된 수학 엔진을 가진 도구가 되었습니다.이전글목록으로다음글저작권 고시Copyright Notice본 웹사이트의 모든 디자인 결과물 및 영상에 대한 저작권은 Abstract Cloud에 있으며, 저작권법 및 관련 법령에 의해 보호받습니다. 웹, 영상, 본문, 표지, 내지 디자인을 포함한 모든 콘텐츠는 저작권자의 자산으로, 사전 동의 없이 무단 복제, 배포, 2차 저작물 제작, 온라인 공유 등을 금지합니다. 이를 위반할 시, 저작권법에 따라 민형사상 책임을 질 수 있습니다. 정당한 구매와 저작권 보호는 창작자의 권리를 지키며, 더 나은 작품으로 보답할 힘이 됩니다.저작권자: Abstract Cloud | 대표자: 배창규(uragen)
© Abstract Cloud. All Rights Reserved.
HOMEFAQ이용 약관개인정보 이용방침help@opkle.app
010-2747-3403
상호 :추상적 형상 디자인(Abstract cloud)  |  대표자 :배창규사업자등록번호 :249-74-00533통신판매업 신고번호 :2025-의정부송산-0634주소 :경기도 의정부시 부용로 49, 108동 402호웹의 모든 콘텐츠, 디자인, 소스 코드에 대한
저작권은 Opkle에게 있습니다.
img default description