- Wheel Reinvention Jam의 “기존 소프트웨어를 새 시각으로 다시 보기”라는 과제에서 ShapeUp이 탄생했고, 브라우저 실행 데모와
.obj내보내기까지 갖춘 3D 모델러로 완성됨 - 일주일 안에 3D 도구를 만들 수 있었던 핵심은 ray marched SDF였으며, 삼각형 기반 렌더러보다 색상·부드러운 그림자·ambient occlusion이 있는 장면을 빠르게 구현할 수 있었음
- 구현은 C 단일 파일 중심으로 단순하게 유지됐고, 모델은 최대 100개 Shape를 정적 배열에 담아 메모리 관리 부담을 줄임
- raylib는 OpenGL 창을 빨리 띄우는 데 도움을 줬지만,
int중심 API, 매개변수 검증 부재, GLFW 의존성, raygui 한계 때문에 직접 OpenGL을 쓰거나 기능을 새로 만들어야 했음 - 최종 결과물은 C 2024줄과 GLSL 250줄, 총 약 2300줄 규모로 파일 열기·저장, 여러 플랫폼 실행,
.obj내보내기를 지원함
ShapeUp이 3D 모델러로 바뀐 과정
- Wheel Reinvention Jam은 기존 소프트웨어 시스템을 새 시각으로 다시 살펴보는 일주일짜리 프로그래밍 이벤트였음
- 처음 목표는 느린 TypeScript 컴파일러에 대한 불만에서 출발해
tsc보다 빠른 TypeScript 부분집합을 만드는 것이었음esbuild나Bun의 TypeScript 파서를 시작점으로 삼으면 가능해 보였음- 하지만 성공 데모가 “한 터미널 명령이 다른 명령보다 빨리 끝남”에 그쳐 시각적으로 매력적이지 않았고, 결국 3D로 방향을 틀었음
- ShapeUp은 마우스로 도형을 편집하는 3D 모델러로 만들어짐
- 기존 SDF 셰이더 작성 경험은 있었지만, 코드를 직접 수정해 모델링하는 방식은 자연스럽지 않았음
- 목표는 SDF 기반 형태 편집을 마우스로 할 수 있게 만드는 것이었음
SDF가 일주일 프로젝트를 가능하게 한 이유
- ShapeUp의 렌더링 기반은 ray marched signed distance fields(SDFs) 임
- SDF 장면은 색상, 부드러운 그림자, ambient occlusion을 포함해도 삼각형 기반 렌더러보다 빠르게 구현할 수 있었음
- Inigo Quilez가 SDF로 한 자리에서 Pixar풍 캐릭터를 만드는 사례가 기술적 방향의 참고점이 됨
- ShapeUp은 코드 편집 대신 도형을 직접 조작하는 방식으로 SDF 모델링을 다룸
C 구현과 데이터 구조
- ShapeUp은 C로 작성됐고, OpenGL 창 생성을 위해 raylib를 사용함
- C를 고른 이유는 빠른 컴파일, 복잡한 동작을 숨기지 않는 문법, 익숙함, 네이티브와 WebAssembly 양쪽 컴파일 가능성 때문임
- 모델은
Shape구조체들의 집합으로 구성됨- 각 Shape는 위치, 크기, 각도, 모서리 반경, blob 정도, 색상, 미러링 축, subtract 여부를 가짐
- Shape 목록은 동적 할당 대신 정적 배열로 관리됨
MAX_SHAPE_COUNT는 100Shape shapes[MAX_SHAPE_COUNT],shape_count,selected_shape로 상태를 관리함- 이 방식은 할당 실패와 누수 가능성을 없앰
- 100개 Shape 제한은 실제 사용에서 큰 문제가 되지 않았음
- 렌더러 최적화 시간이 부족해 100개에 도달하기 전에 프레임레이트가 먼저 떨어졌음
- 시간이 있었다면 모델을 작은 벽돌 단위로 나누고 각 벽돌 안에서 ray marching을 수행하려 했음
메모리 사용 방식
- ShapeUp은 동적 메모리 할당을 3곳에서만 사용함
- 저장: 전체 문서를 담을 수 있는 버퍼 할당
.OBJ내보내기: 모든 정점을 담을 수 있는 버퍼 할당- GLSL 셰이더 생성: 셰이더 소스용 버퍼 할당
- 각 경우 함수 끝에서 한 번만
free함 - Shape를 각각
malloc하고 포인터를 동적 배열에 저장할 수도 있지만, 이 프로젝트에는 그런 구조가 필요하지 않았음 - C는 메모리 배치를 직접 제어할 수 있다는 점에서 장점이 있었음
- 동적 배열이나 해시맵이 필요했다면
stb_ds.h같은 도구를 쓸 수 있었음
UI 구현 방식
- UI는 immediate mode user interface(IMGUI) 방식으로 구현됨
- IMGUI는 디버깅이 쉽고, CSS·constraints·SwiftUI 대신 실제 프로그래밍 언어로 요소 위치를 정할 수 있다는 점이 장점임
- 포커스된 요소나 마우스 동작은
Controlenum으로 추적함- 위치, 크기, 각도, 색상, 이동, 회전, 스케일, 카메라 회전, blob 정도 같은 조작 상태를 enum 값으로 표현함
focused_control과mouse_action이 현재 UI 상태를 담음
raylib와 raygui에서 막힌 지점
- raylib는 OpenGL 창을 빠르게 띄우는 데는 유용했지만, 시간이 지날수록 개발 속도를 늦추는 요소가 됨
- raylib API에서 특히 불편했던 부분은 타입 정보 부족이었음
- enum 타입이 기대되는 곳에도
int를 사용해 컴파일러 타입 검사를 받을 수 없음 - 함수 시그니처만으로 매개변수 의미가 잘 드러나지 않음
- 예를 들어
IsGestureDetected(unsigned int gesture)의gesture는 등록된 제스처 ID처럼 보이지만 실제로는Gestureenum임 - 문서가 헤더 파일 중심이라 어떤
int가 실제로 enum인지 확인하려면 구현을 봐야 했음
- enum 타입이 기대되는 곳에도
- 기본 매개변수 검증을 하지 않는 설계도 문제를 키움
LoadFileData(const char *fileName, int * dataSize)는dataSize가NULL이면 segfault가 남- 헤더는
dataSize가 출력 매개변수인지, null이면 안 되는지 표시하지 않음 - 검증 부재 때문에 단순한 문제 추적이 어려워졌고, 경우에 따라 조용히 이상 동작을 할 수 있었음
- 의존성 처리에서도 기대와 차이가 있었음
- GLFW의 이슈를 raylib가 우회하거나 패치를 제출하지 않는 문제가 있었음
- 최종 사용자는 창 생성 방식의 내부 구현보다 raylib 기능이 제대로 동작하는지를 더 중요하게 봄
- raygui UI 라이브러리는 프로젝트에 쓰기엔 제약이 많았음
- 부동소수점 숫자를 표시하지 못해 직접 float 텍스트 필드를 만들어야 했음
- 겹치거나 잘린 요소의 마우스 이벤트 라우팅을 처리하지 못함
- UI에서 흔한 둥근 모서리를 지원하지 못함
- 보기 좋게 스타일링하기 어려움
- 버그도 개발 흐름을 방해함
- raygui 도구 버그 때문에 과하게 스타일화된 기본 폰트를 바꾸지 못했음
DrawCircle(...)같은 그리기 함수는 삼각형 사이에서 정점을 공유하지 않아, 현재 행렬에 스케일이나 회전이 있으면 부동소수점 오차로 픽셀 틈이 생겼음
- 발견한 이슈를 한동안 보고했지만 대부분 “wont fix”로 닫혔고, 이후에는 보고를 중단함
- 우회 방법은 직접 OpenGL 함수를 쓰거나 필요한 기능을 처음부터 구현하는 것이었음
- 앞으로는 raylib 대신 sokol을 사용할 계획임
6일 안에 끝내야 했던 네 가지
- ShapeUp은 6일 안에 크게 네 부분을 완성해야 했음
- 사용자 인터페이스: 3D 기즈모, 키보드 단축키, 사이드바, 게임 컨트롤러
- GLSL 셰이더 생성기와 ray marching 렌더러
- GPU 기반 마우스 선택
- 내보내기용 marching cubes
- 어려움은 각 기능 자체보다 우선순위 유지에 있었음
- 까다롭거나 시간이 오래 걸리는 문제는 설계를 바꿔 피하거나, 90% 경우에 동작하는 단순한 해결책으로 처리함
- 어떤 기능은 하루 미뤄두는 동안 해결책이 떠오르기도 했음
- 작업 방식은 항상 동작하는 3D 모델러를 유지하고, 시간이 허락하는 만큼 점진적으로 개선하는 쪽이었음
- 완성 시점에만 피라미드가 되는 방식이 아니라, 어느 단계에서 멈춰도 완전한 작은 피라미드가 되도록 만드는 방식에 비유됨
최종 결과
- 일주일이 끝날 때 ShapeUp은 의미 있는 3D 모델을 만들고
.obj파일로 내보낼 수 있었음 - 여러 플랫폼에서 실행되고, 파일 열기와 저장도 지원함
- 코드 규모는 C 2024줄과 GLSL 250줄임
- 약 2300줄로 어느 정도 유용한 3D 모델러를 만들 수 있었다는 점이 눈에 띄는 결과임
- 프로젝트 자체는 비교적 단순하지만, 무엇을 만들지 고르는 감각, 만들 수 있는 지식, 일주일 안에 끝내는 규율이 중요하게 작용함