# 일주일 만에 C로 제작한 3D 모델러

> Clean Markdown view of GeekNews topic #14626. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=14626](https://news.hada.io/topic?id=14626)
- GeekNews Markdown: [https://news.hada.io/topic/14626.md](https://news.hada.io/topic/14626.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2024-05-03T10:04:45+09:00
- Updated: 2024-05-03T10:04:45+09:00
- Original source: [danielchasehooper.com](https://danielchasehooper.com/posts/shapeup/)
- Points: 2
- Comments: 1

## Topic Body

### 3D 모델러를 C언어로 일주일 만에 만들기
- 작년 가을에 "Wheel Reinvention Jam"이라는 일주일 동안의 프로그래밍 이벤트에 참여함
- 기존 소프트웨어 시스템을 새로운 시각으로 다시 살펴보는 것이 목적이었음
- "ShapeUp"이라는 3D 모델러를 만들었고, 이 글을 읽기 전에 ShapeUp의 데모 동영상을 먼저 보는 것이 이해에 도움됨
- ShapeUp은 브라우저에서 직접 사용해 볼 수 있음

### 언어 선택: C
- Typescript 컴파일러가 느린 것에 대한 불만으로 인해 Jam에 참여
- esbuild나 Bun의 Typescript 파서로 시작한다면 Typescript의 빠른 부분 집합을 구현하는 프로젝트가 가능해 보였음
- 하지만 터미널 명령어 실행 속도 비교로는 흥미로운 데모가 되지 않을 것 같아 3D 프로젝트로 방향을 전환함
- Ray marched signed distance fields(SDFs) 기술 덕분에 일주일 만에 처음부터 3D 프로젝트를 만드는 것이 가능해 보였음
- 동등한 삼각형 기반 렌더러보다 SDF를 사용한 장면이 훨씬 빠르게 구현 가능
- 이전에 SDF 셰이더를 작성해본 적은 있었지만 매우 기초적인 수준이었고, 코드를 편집하여 모델링하는 것은 자연스럽지 않게 느껴졌음
- 마우스로 모양을 편집하고 싶었고, 이번 Jam이 그것을 실현할 기회라고 생각했음
- 프로젝트 이름을 ShapeUp이라고 지음

### C언어 사용의 장점
- C는 매우 단순하고 원시적인 언어여서 내장 데이터 구조의 부족을 해결하고 포인터 버그를 고치는데 많은 시간을 소비할 것이라고 여겨짐
- 하지만 C의 단순성은 장점이 됨
  - 빠르게 컴파일 됨
  - 문법이 복잡한 연산을 숨기지 않음 
  - 간단해서 끊임없이 문법을 찾아볼 필요가 없음
  - native와 web assembly로 쉽게 컴파일 가능
- C의 결점들은 22년 동안 사용하면서 개발한 습관으로 피할 수 있음
- ShapeUp은 작은 단일 C 파일로 구성되어 매우 간단함

### ShapeUp의 데이터 구조
- 모델은 Shapes라는 구조체의 배열로 구성됨
- Shapes는 정적으로 할당된 배열에 저장됨
  - 할당 실패나 메모리 누수의 위험이 없음
  - 100개의 Shape 제한은 실제로는 제한적이지 않았음
  - 렌더러 최적화 시간이 부족하여 100개가 되기 전에 프레임 속도가 떨어졌을 것
  - 시간이 있었다면 모델을 작은 블록으로 나누고 각 블록 내에서 raymarching을 수행했을 것
- 동적 메모리는 단 3곳에서만 malloc을 호출함
  - 저장 (전체 문서를 담을 수 있을 만큼 큰 버퍼 할당)
  - OBJ 내보내기 (모든 꼭지점을 담을 수 있을 만큼 큰 버퍼 할당)
  - GLSL 셰이더 생성 (셰이더 소스용 버퍼)
- 모든 경우 함수 끝에 단일 free가 있음
- C에서 메모리 관리가 간단할 수 있다는 것을 보여주는 예시
- C#, Javascript, Python 같은 언어는 Shape마다 개별적으로 malloc하고 해당 포인터를 동적 배열에 저장하는 할당 구조를 강제함
- C는 메모리 레이아웃을 제어할 수 있어서 좋음

### 사용자 인터페이스
- immediate mode user interface(IMGUI)로 구현됨
- IMGUI 방식의 UI를 좋아함
  - 디버깅이 매우 쉬움
  - 요소를 배치하기 위해 실제 프로그래밍 언어 사용 (CSS, constraints, SwiftUI와 달리)
- 대부분의 IMGUI와 마찬가지로 enum을 사용하여 어떤 요소에 포커스가 있는지 또는 마우스가 어떤 동작을 하고 있는지 추적함
- 이 프로젝트에는 동적 배열이나 해시맵이 필요하지 않았지만, 필요했다면 stb_ds.h와 같은 것을 사용했을 것

### Raylib 라이브러리의 문제점
- C를 사용하기로 결정한 것은 좋았지만, raylib은 문제가 됨
- 개발자 경험을 해치는 이상한 설계 선택이 있음
  - enum 타입이 예상되는 곳에 int를 사용하여 컴파일러 타입 검사를 방지하고 함수가 self document 되지 않음 
  - 기본 매개변수 유효성 검사를 하지 않음 (설계 선택)
  - 종속성에 대한 책임을 지지 않음 (GLFW 이슈를 해결하거나 패치를 제출하지 않음)
- raygui UI 라이브러리는 장난감에 불과함
  - 부동 소수점 숫자를 표시할 수 없음
  - 겹치거나 클리핑된 요소에 대한 마우스 이벤트 라우팅을 처리하지 않음
  - 둥근 모서리를 만들 수 없음
  - 보기 좋게 스타일을 지정할 수 없음
- 버그도 있음 
  - 폰트 변경 방지 버그
  - 그리기 함수가 삼각형 사이의 꼭지점을 공유하지 않아 픽셀 간격이 발생
- 문제를 발견할 때마다 보고했지만 대부분 "won't fix"로 닫혔고 버그 리포트 작성에 시간이 많이 걸려 포기함
- OpenGL 창을 만들어준 것은 좋았지만 그 편의성에 큰 대가를 치름
- 다행히 OpenGL 함수를 직접 사용하거나 기능을 처음부터 구현하는 탈출구를 찾을 수 있었음
- 앞으로는 sokol을 사용할 예정

### 일주일 동안의 개발 과정
- ShapeUp은 6일 동안 완료해야 하는 4가지 주요 부분으로 구성됨
  1. 사용자 인터페이스 (3D 도구, 키보드 단축키, 사이드바, 게임 컨트롤러)
  2. GLSL 셰이더 생성기 + Ray marching 렌더러
  3. GPU 기반 마우스 선택
  4. Marching cubes for export
- 각각은 어렵지 않았지만, 우선순위를 올바르게 정하고 빠져나가지 않는 것이 어려웠음
- 까다롭거나 시간이 많이 걸리는 문제는 설계를 통해 해결하거나 90% 경우에 작동하는 멍청한 해결책을 사용하는 것이 도움됨
- 때로는 기능을 하루 정도 미루면 무의식적으로 해결책을 찾을 수 있었음  
- 항상 작동하는 3D 모델러를 가지고 있고 시간이 허락하는 대로 점진적으로 개선하려고 노력함
- 피라미드를 만드는 것처럼 생각함. 층별로 만들면 마지막까지 피라미드가 완성되지 않지만, 어느 단계에서 멈추더라도 완전한 피라미드가 되도록 만들 수 있음

### 프로젝트 결과
- 일주일 후에는 의미 있는 3D 모델을 만들고 .obj 파일로 내보낼 수 있는 3D 프로그램을 가지게 됨 
- 멀티플랫폼에서 실행되고 파일 열기/저장 기능도 있음
- 프로젝트는 2024줄의 C코드와 250줄의 GLSL로 구성됨
- 약 2300줄 정도로 어느 정도 쓸모 있는 3D 모델러를 표현할 수 있다는 것이 약간 놀라움
- Jam 요약과 Handmade Seattle 컨퍼런스에서 ShapeUp 데모를 보여달라는 요청을 받음
- 사람들은 ShapeUp에 감명을 받은 듯 했지만 큰 성과를 거둔 것 같지는 않음. 비교적 간단한 프로젝트임
- 내가 한 일에 특별한 것이 있다면, 무엇을 만들지 선택할 수 있는 감각, 그것을 만드는 데 필요한 지식, 그리고 일주일 안에 해내는 규율이었음

### GN⁺의 의견
- C언어의 단순함과 속도의 장점을 잘 보여주는 흥미로운 프로젝트임. 하지만 C의 낮은 추상화 수준 때문에 상용 프로젝트에 그대로 사용하긴 어려워 보임. 현대적인 3D 모델링 도구의 기능을 모두 C로 직접 구현하려면 엄청난 노력이 필요할 것으로 예상됨
- 일주일 만에 동작하는 프로그램을 완성한 것이 인상적임. 하지만 장기적인 관점에서 코드 유지보수와 기능 확장을 고려했을 때 C++이나 Rust 같은 언어를 선택하는 것이 더 나은 선택일 수 있음
- SDF를 이용한 렌더링 기법은 빠르고 간단하지만 모델링의 자유도나 퀄리티 면에서는 한계가 있어 보임. 상용 모델링 툴은 SubD나 NURBS 같은 표면 모델링 기술을 주로 사용함. 하지만 게임이나 데모 등 실시간성이 중요한 분야에서는 SDF 렌더링이 여전히 활용 가치가 높아 보임
- 오픈소스 라이브러리 선택의 어려움을 잘 보여주는 사례. 문서화와 코드 품질, 지원 여부 등을 잘 파악하고 신중하게 선택해야 함. 자체 구현도 좋은 대안이 될 수 있음 
- 동작하는 프로그램을 먼저 만들고 점진적으로 개선해 나가는 방식은 실무에서도 매우 유용함. 핵심 기능부터 완성하고 세부 사항을 개선하는 식으로 우선순위를 잘 조절하는 것이 중요해 보임

## Comments



### Comment 24904

- Author: neo
- Created: 2024-05-03T10:04:45+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=40239164) 
* Raylib의 한계점에 대해 저자와 전적으로 동의함
  - 현재 Raylib으로 시작한 타워 디펜스 스타일 게임 개발 중이지만 비슷한 제한 사항에 직면함
  - 플랫폼 간 전체 화면 전환 불일치, 화면 모드 열거 불가, 런타임 렌더링 기능 전환 불가, 컴파일된 셰이더 저장 불가 등의 이슈가 있음
  - Raylib은 프로토타입 제작에는 좋지만 심각한 제한 사항을 감수하지 않는 한 그 이상은 어려움
  - 개발이 너무 진행되어 이제 Raylib을 SDL 등으로 교체하기에는 늦음
* 형상을 정적 할당된 배열에 보관하는 것은 할당 실패나 메모리 누수 위험이 없는 사랑스러운 방식임. 실제로 100개 형상 제한은 제약이 되지 않음.
* 이 프로젝트가 계속 발전하길 바람. 몇 달 후면 학습 곡선이 훨씬 완만한 Blender/FreeCAD의 특정 사용 사례에 대한 진지한 대안이 될 수 있음.
* 영상의 라이브 데모가 정말 마음에 듦. 앱 제작은 고사하고 그런 영상을 1주일 만에 만들 수 없을 것임.
* 메모리 처리 등 다양한 결정에 대해 이야기한 흥미로운 글. Crafting Interpreters 2부에 뛰어들면서 C 언어를 다시 공부하는 입장에서 C가 잘하는 것이 무엇인지 상기시켜 줌.
* 2024줄의 C 코드로 아이러니를 가능케 한 노력에 감사함 :)
* 잘 아는 도구를 가지고 그냥 멋진 것을 만드는 데에는 정말 강력한 무언가가 있음. 글 잘 읽었음.
* C에 대한 주장에 정말 동의함. 특히 "문법이 복잡한 연산을 숨기지 않음. 간단해서 계속 찾아볼 필요가 없음"에 더욱 공감. 또한 C에 대해 뭔가 찾아봐야 한다면 매우 쉽고 유익함. 단순하고 오래된 언어의 장점임.  
* 가끔 C가 우리에게 필요한 전부라고 생각함.
* 인상적인 개발 속도임. 설명 영상도 정말 재미있게 봤음!
