1993년식 그래픽으로 돌아가기: Catlantean 3D가 증명한 ‘제한된 자원’의 미학

대표 이미지

1993년식 그래픽으로 돌아가기: Catlantean 3D가 증명한 '제한된 자원'의 미학

최신 하드웨어 위에서 320×240 소프트웨어 렌더링을 구현하며 깨달은 레트로 그래픽의 기술적 트레이드오프

가끔 최신 게임들을 보면 “이제 더 이상 발전할 곳이 있나?” 싶을 때가 있어요. 모든 게 너무 매끄럽고 사실적이라 오히려 개성이 없게 느껴지기도 하죠. 그러다 최근 ‘Catlantean 3D’라는 프로젝트를 발견했는데, 정말 흥미롭더라고요. 320×240라는 극단적인 저해상도에 256색상만 사용하는 소프트웨어 렌더링 방식을 택했거든요. 소위 ‘감자’라고 부르는 아주 낮은 사양의 PC에서도 돌아가도록 아카이익(Archaic)한 기술 체계를 그대로 구현한 거죠 [1].

사실 요즘 같은 시대에 굳이 이렇게까지 해야 하나 싶으실 거예요. 하지만 제가 본 바로는, 현대의 압도적인 컴퓨팅 파워 시대에도 의도적인 기술적 제약(Low-poly, Rasterization)은 독특한 미학적 정체성과 극단적인 최적화를 동시에 잡는 아주 영리한 전략이 됩니다.

왜 다시 1993년인가: 소프트웨어 렌더링의 귀환

요즘은 GPU가 없으면 게임 개발이 불가능하다고 생각하시죠? 하지만 소프트웨어 렌더링은 GPU 가속 없이 오직 CPU만으로 픽셀 하나하나의 색상을 계산하는 방식이에요. Catlantean 3D는 C++ 기반의 레이캐스터(Raycaster)를 사용해 이 방식을 구현했는데요 [1], 최신 언어를 쓰면서도 렌더링 기법은 90년대 초반으로 돌아간 묘한 결합을 보여줍니다.

여기서 핵심은 320×240 해상도와 256색이라는 제약이에요. 이게 단순히 ‘화질이 나쁜 것’이 아니라, 화면 전체에 일관된 시각적 톤을 만들어주는 하나의 ‘스타일’이 되거든요. 요즘 유행하는 ‘부머 슈터(Boomer Shooter)’ 장르가 바로 이런 하드웨어적 제약을 미학으로 승화시킨 대표적인 사례라고 할 수 있습니다.

“320×240 software rendering with 256 colors, runs on a potato.” [1]

(256색상의 320×240 소프트웨어 렌더링으로, 아주 저사양 PC에서도 구동됩니다.)

이런 렌더링 루프를 아주 단순하게 구현하면 대략 이런 느낌이 됩니다.

// 아주 단순화된 소프트웨어 렌더링 픽셀 채우기 예시
void draw_pixel(int x, int y, uint32_t color) {
    // 화면 버퍼의 특정 좌표에 직접 색상 값을 씁니다.
    // GPU를 거치지 않고 CPU가 메모리에 직접 접근하는 방식이죠.
    uint32_t* screen_buffer = get_frame_buffer(); 
    screen_buffer[y * SCREEN_WIDTH + x] = color; 
}

void render_frame() {
    for (int y = 0; y < 240; ++y) { // Y축 스캔
        for (int x = 0; x < 320; ++x) { // X축 스캔
            uint32_t color = calculate_pixel_color(x, y); // 픽셀 색상 계산
            draw_pixel(x, y, color);
        }
    }
}

이 코드를 보면 알 수 있듯이, 복잡한 셰이더 파이프라인 없이 CPU가 루프를 돌며 픽셀을 하나씩 찍어내는 구조예요. 투박하지만 그만큼 통제감이 확실하죠.

Low-Poly의 경제학: 폴리곤 개수와 성능의 상관관계

그다음으로 짚어볼 건 ‘로우폴리(Low-poly)’입니다. 사실 로우폴리는 단순한 취향의 문제가 아니라 철저한 ‘경제학’의 산물이에요. 폴리곤 수(Polygon Count)가 많아질수록 디테일은 살아나지만, 그만큼 렌더링 속도는 느려질 수밖에 없거든요 [2].

보통 로우폴리 모델은 실시간 렌더링 최적화를 위해 10,000개 미만의 폴리곤을 사용합니다 [3]. 하이폴리 모델이 수백만 개의 폴리곤으로 매끄러운 곡선을 만든다면, 로우폴리는 최소한의 삼각형으로 형태만 잡는 식이죠. 여기서 중요한 게 ‘리토폴로지(Retopology)’ 과정이에요. 복잡한 메쉬 구조를 단순화해서 렌더링 효율을 극대화하는 작업인데, 덕분에 어떤 디지털 플랫폼에서도 가볍게 돌아갈 수 있게 됩니다 [4].

결국 하이폴리의 정교함과 로우폴리의 효율성 사이에서 줄타기를 하는 셈인데, 레트로 스타일에서는 후자를 선택함으로써 얻는 ‘속도’와 ‘특유의 각진 느낌’을 정체성으로 삼는 거죠.

래스터라이제이션(Rasterization)과 픽셀의 세계

그렇다면 이 3D 데이터가 어떻게 우리 눈에 보이는 2D 화면으로 바뀔까요? 여기서 ‘래스터라이제이션(Rasterization)’이라는 개념이 나옵니다. 쉽게 말해 3D 좌표를 2D 픽셀 그리드로 변환하는 과정이에요. 래스터 그래픽은 수학적 공식이 아니라, 각 픽셀의 정확한 색상 값을 저장하는 2D 그리드 형태를 띱니다 [5].

전통적인 방식 중 하나인 ‘스캔라인(Scanline)’ 렌더링은 폴리곤의 Y좌표 상단부터 한 줄씩 훑으며 2D 이미지로 변환하는 기법이에요 [6]. 여기에 ‘Z-버퍼(Z-Buffer)’를 더하면, 각 픽셀의 깊이 값을 저장해 어떤 물체가 앞에 있고 뒤에 있는지 판단할 수 있죠.

특히 색상 팔레트가 제한적일 때, 부족한 색상을 보완하기 위해 점을 섞어 쓰는 ‘디더링(Dithering)’ 효과가 나타나는데, 이게 바로 우리가 기억하는 그 90년대 게임 특유의 질감을 만들어냅니다.

// Z-버퍼를 이용한 가시성 판단의 핵심 로직 (의사코드)
void rasterize_triangle(Triangle tri) {
    for (int y = tri.min_y; y <= tri.max_y; ++y) {
        for (int x = tri.min_x; x <= tri.max_x; ++x) {
            float depth = calculate_depth(x, y, tri); // 현재 픽셀의 깊이 계산
            
            // 저장된 깊이 값보다 현재 픽셀이 더 앞에 있을 때만 그립니다.
            if (depth < z_buffer[y][x]) { 
                z_buffer[y][x] = depth; // 깊이 값 업데이트
                set_pixel(x, y, tri.color); // 픽셀 색상 지정
            }
        }
    }
}

이 짧은 조건문 하나가 3D 공간의 ‘앞뒤 관계’를 결정짓는 아주 강력한 도구가 됩니다.

짚고 넘어갈 한계와 안티패턴

물론 무작정 “옛날 방식으로 만들면 되겠지”라고 생각했다가는 함정에 빠지기 쉽습니다. 가장 흔한 실수가 단순히 폴리곤 수만 줄이는 거예요. ‘의도된 로우폴리 미학’은 단순한 저품질이 아니라, 제한된 자원 속에서 형태를 어떻게 효율적으로 표현하느냐의 예술이거든요.

또한, 현대적인 셰이더를 잔뜩 얹은 채 해상도만 낮춘 ‘가짜 레트로’는 묘한 이질감을 줍니다. 픽셀의 계단 현상(Aliasing)을 제대로 제어하지 못하면 그냥 ‘지저분한 화면’이 될 뿐이죠. 무엇보다 소프트웨어 렌더링은 GPU의 병렬 처리 능력을 완전히 무시하고 CPU에 모든 짐을 지우기 때문에, 렌더링 루프를 잘못 설계하면 최신 PC에서도 프레임 드랍이 발생하는 CPU 병목 현상을 겪게 됩니다 [6].

아울러 로우폴리 모델은 태생적으로 리얼리즘이 부족해요. 그래서 클로즈업 뷰나 아주 정밀한 표현이 필요한 애플리케이션에는 적합하지 않다는 점을 명심해야 합니다 [3].

핵심 요약

  • 레트로 그래픽의 핵심은 단순한 ‘낮은 품질’이 아니라 ‘의도된 제약’의 일관성입니다.
  • 로우폴리 모델링은 실시간 렌더링 효율성을 극대화하는 가장 강력한 방법입니다.
  • 래스터라이제이션의 기본 원리를 이해하면 최신 엔진을 쓸 때도 최적화 지점을 정확히 찾을 수 있습니다.
  • 최신 하드웨어에서도 ‘감자’ 사양을 타겟팅하는 것은 전 세계 누구에게나 접근성을 제공하는 영리한 전략이 됩니다.

사실 요즘은 버튼 하나만 누르면 화려한 그래픽이 나오는 시대잖아요. 하지만 픽셀 하나하나를 직접 제어하고, 1993년의 한계를 재현하며 고민하는 과정에서 느끼는 ‘통제감’은 정말 특별하더라고요. 결국 기초가 탄탄해야 그 위에 어떤 화려한 기술을 얹어도 흔들리지 않는다는 걸 다시 한번 깨닫게 됩니다.


References

1. [youtube.com] Catlantean 3D – Early Gameplay (C++ raycaster) — https://www.youtube.com/watch?v=EHTu0CRlM9k 2. [caddesignhelp.com] What is the difference between low-poly and high-poly 3D models? — https://caddesignhelp.com/2022/03/what-is-the-difference-between-low-poly-and-high-poly-3d-models 3. [taangastudios.com] Low Poly vs High Poly 3D Models : Things You Should Know — https://www.taangastudios.com/post/what-are-low-poly-and-high-poly-3d-models 4. [cgifurniture.com] High-Poly vs Low-Poly 3D Models: Key Differences — https://cgifurniture.com/blog/high-poly-models-vs-low-poly-ones 5. [wikipedia.org] Raster graphics — https://en.wikipedia.org/wiki/Raster_graphics 6. [3d-ace.com] Different Rendering Techniques: Pros, Cons and Tips — https://3d-ace.com/blog/different-rendering-techniques

관련 글 추천

  • https://infobuza.com/2026/06/09/20260609-yuvi7d/
  • https://infobuza.com/2026/06/09/20260609-ymk1kf/

FAQ

Catlantean 3D 프로젝트의 그래픽 특징은 무엇인가요?

320×240의 극단적인 저해상도와 256색상만을 사용하는 소프트웨어 렌더링 방식을 채택하여, 아주 낮은 사양의 PC에서도 구동 가능하도록 구현되었습니다.

소프트웨어 렌더링이란 무엇이며 어떻게 작동하나요?

GPU 가속 없이 오직 CPU만으로 픽셀 하나하나의 색상을 계산하는 방식입니다. Catlantean 3D의 경우 C++ 기반의 레이캐스터를 사용해 이를 구현했습니다.

로우폴리(Low-poly) 모델의 장점과 특징은 무엇인가요?

실시간 렌더링 최적화를 위해 보통 10,000개 미만의 폴리곤을 사용하며, 하이폴리 모델보다 렌더링 속도가 빠르고 어떤 디지털 플랫폼에서도 가볍게 돌아갈 수 있다는 효율성이 특징입니다.

래스터라이제이션(Rasterization)과 Z-버퍼의 역할은 무엇인가요?

래스터라이제이션은 3D 좌표를 2D 픽셀 그리드로 변환하는 과정이며, Z-버퍼는 각 픽셀의 깊이 값을 저장하여 어떤 물체가 앞에 있고 뒤에 있는지 판단하는 역할을 합니다.

소프트웨어 렌더링 방식을 사용할 때 주의해야 할 한계점은 무엇인가요?

GPU의 병렬 처리 능력을 무시하고 CPU에 모든 부하를 주기 때문에, 렌더링 루프 설계가 잘못되면 최신 PC에서도 CPU 병목 현상으로 인한 프레임 드랍이 발생할 수 있습니다.

보조 이미지 1

보조 이미지 2

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다