Skip to main content

Command Palette

Search for a command to run...

3D 그래픽스를 한 줄 공식으로 풀어내는 비법 – 초보자도 바로 이해하는 3D 변환 공식

Published
•4 min read•View as Markdown

# 서론 – “왜 3D 그래픽스가 이렇게 어려워 보일까?”

컴퓨터 그래픽스를 처음 접하는 사람들은 ‘3D 그래픽스는 복잡하고 어려워 보인다’는 느낌을 쉽게 받습니다.

수많은 행렬, 좌표계, 카메라 설정… 어디서부터 시작해야 할지 막막하죠.

하지만 실제로 3D 공간을 화면에 투사하는 핵심은 단 하나의 공식에 의해 설명될 수 있습니다. 이 글에서는 그 공식과 원리를 차근차근 풀어내어, 초보자도 “이제 이해했어!”라고 외칠 수 있도록 도와드립니다.

키워드: 3D 그래픽스, 3D 변환 공식, 컴퓨터 그래픽스 기초


# 본론

# 1️⃣ 3D 그래픽스의 기본 개념 – 좌표와 행렬

3D 그래픽스는 ‘점(Point) → 선(Line) → 면(Face)’ 로 구성된 모델을 화면에 그리는 과정입니다.

이때 각 점은 (x, y, z) 로 표현되는 3차원 좌표를 가지고, 이를 2차원 화면에 투사하려면 행렬(Matrix) 연산이 필요합니다.

  • 모델 행렬(Model Matrix) : 객체를 자신의 로컬 좌표계에서 월드 좌표계로 옮깁니다.

  • 뷰 행렬(View Matrix) : 카메라(시점)를 설정해 월드 좌표를 카메라 좌표계로 변환합니다.

  • 프로젝션 행렬(Projection Matrix) : 원근감(퍼스펙티브) 또는 평행 투영을 적용해 3D 좌표를 2D 화면 좌표로 바꿉니다.

이 세 행렬을 차례대로 곱하면 ‘월드 → 카메라 → 화면’ 으로 변환되는 최종 변환 행렬이 만들어집니다.

# 2️⃣ 한 줄 공식 – MVP 행렬의 완전한 형태

위에서 언급한 세 행렬을 하나로 합친 것이 바로 MVP 행렬입니다.

[

\boxed{ \mathbf{p}{\text{clip}} = \mathbf{Projection} \times \mathbf{View} \times \mathbf{Model} \times \mathbf{p}{\text{local}} }

]

  • \mathbf{p}_{\text{local}} : 모델 자체의 로컬 좌표(정점)

  • \mathbf{Model} : 모델 행렬

  • \mathbf{View} : 뷰 행렬

  • \mathbf{Projection} : 프로젝션 행렬

  • \mathbf{p}_{\text{clip}} : 클리핑 공간(렌더링 파이프라인에 넘겨지는 최종 좌표)

이 한 줄 공식만 기억하면, ‘어떤 객체를 어디에, 어떤 시점에서, 어떤 카메라 렌즈로 볼 것인가’ 라는 3D 그래픽스의 핵심 질문에 답을 줄 수 있습니다.

# 왜 ‘곱셈 순서’가 중요한가?

행렬 곱은 교환법칙이 성립하지 않기 때문에, Model → View → Projection 순서대로 곱해야 합니다.

예를 들어, 카메라가 움직였을 때 모델이 따라 움직이는 것이 아니라, 카메라가 모델을 바라보는 형태가 됩니다. 이 점을 놓치면 “카메라가 움직이면 모델이 뒤틀린다”는 이상 현상이 발생합니다.

# 3️⃣ 실제 코드 예시 – OpenGL/DirectX에서 MVP 적용하기

아래는 C++과 GLSL(또는 HLSL)에서 MVP 행렬을 만든 뒤, 정점 셰이더에 전달하는 간단한 예시입니다.

cpp

// C++ (GLM 라이브러리 사용)

glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(2.0f, 0.0f, -5.0f));

glm::mat4 view  = glm::lookAt(glm::vec3(0.0f, 1.0f, 3.0f),

                              glm::vec3(0.0f, 0.0f, 0.0f),

                              glm::vec3(0.0f, 1.0f, 0.0f));

glm::mat4 proj  = glm::perspective(glm::radians(45.0f),

                                   (float)width/height,

                                   0.1f, 100.0f);

glm::mat4 MVP = proj * view * model;   // 한 줄 공식!

glUniformMatrix4fv(mvpLocation, 1, GL_FALSE, &MVP[0][0]);
glsl

// Vertex Shader (GLSL)

# version 330 core

layout(location = 0) in vec3 aPos;

uniform mat4 MVP;

void main()

{
    gl_Position = MVP * vec4(aPos, 1.0);

}

위 코드에서 MVP 변수를 한 번만 계산하고 정점 셰이더에 전달하면, GPU는 각 정점을 자동으로 변환해 화면에 그릴 수 있습니다. 복잡한 연산을 CPU가 미리 수행해 주는 것이므로 성능도 최적화됩니다.

# 4️⃣ 초보자를 위한 팁 – 시각화와 디버깅

  1. 행렬을 직접 출력해 보세요

    glm::to_string(MVP) 같은 함수를 이용해 행렬 값을 콘솔에 출력하면, 각 요소가 어떻게 변했는지 눈으로 확인할 수 있습니다.

  2. 단위 큐브를 활용한 테스트

    원점에 있는 1×1×1 크기의 단위 큐브를 그린 뒤, model, view, projection을 하나씩 바꾸어 보세요.

    • 모델 행렬만 바꾸면 큐브가 이동·회전합니다.

    • 뷰 행렬을 바꾸면 카메라 시점이 변합니다.

    • 프로젝션 행렬을 바꾸면 원근감이 달라집니다.

  3. 디버깅 툴 사용

    RenderDoc, NVIDIA Nsight 같은 그래픽 디버거를 이용하면 프레임마다 실제 MVP 행렬과 변환된 정점 위치를 확인할 수 있습니다.

# 5️⃣ 3D 변환 공식의 확장 – 애니메이션과 조명까지

MVP 행렬이 기본 변환을 담당한다면, 추가적인 행렬은 특수 효과를 담당합니다.

| 목적 | 추가 행렬 | 설명 |

|------|-----------|------|

| 애니메이션 | 스키닝 행렬(Skinning Matrix) | 본(bone) 변환을 적용해 캐릭터 움직임 구현 |

| 조명 | 노멀 행렬(Normal Matrix) | 법선 벡터를 올바르게 변환해 라이트 계산 |

| 포스트 프로세싱 | 스크린 공간 변환 | 화면 좌표를 다시 월드 좌표로 복원(디버깅용) |

하지만 이 모든 행렬도 결국 ‘행렬 곱’이라는 동일한 원리 위에 얹혀 있다는 점을 기억하면, 복잡한 파이프라인도 차근차근 이해할 수 있습니다.


# 결론 – 이제 직접 3D 그래픽스를 만들 차례입니다!

“한 줄 공식”만 제대로 이해하고 적용한다면, 3D 그래픽스의 가장 큰 장벽은 사라집니다.

  1. MVP 행렬을 직접 구현해 보세요.

  2. 단위 큐브를 가지고 변환을 실험하면서 직관을 키우세요.

  3. 디버깅 툴로 결과를 검증하고, 점차 애니메이션·조명 같은 고급 기능을 추가해 보세요.

행동 유도: 오늘 바로 코드 편집기를 열고, 위 예시를 복사·실행해 보세요. 작은 성공이 쌓이면, 곧 여러분만의 3D 게임 엔진도 만들 수 있습니다!


이 글은 ‘One Formula That Demystifies 3D Graphics’를 한국어 초보자용으로 재해석한 내용이며, 더 자세한 내용은 원본 Reddit 스레드를 참고하시기 바랍니다.

More from this blog

개발자 vs AI: 연말에 되돌아보는 내가 되고 싶은 개발자 유형은 무엇일까?

# 서론 – 연말, 개발자의 일상이 왜 달라지는가 12월이 되면 많은 개발자들은 데드라인이 느려지고, 팀 채팅은 조용해지며, 풀 리퀘스트(PR)는 한가해지는 것을 경험합니다. “올해는 정말 바빴다”는 감회와 함께, 동시에 “다음 해에는 어떤 개발자가 되고 싶을까?” 하는 고민이 자연스럽게 떠오릅니다. 특히 최근 AI 기술이 급격히 발전하면서, “AI가 내 일을 빼앗을까?” 라는 불안감과 “AI와 협업하면 내 역량을 어떻게 강화할 수 있을까?” ...

Dec 29, 20255 min read

인사이트 부채(Insight Debt)란? 초보 개발자를 위한 쉬운 이해와 해결 방법

# 서론 – 왜 우리는 “인사이트 부채”에 주목해야 할까? 소프트웨어 개발 현장에서 인사이트 부채(Insight Debt) 라는 용어를 들어본 적이 있나요? 프로젝트를 진행하면서 “이 부분은 나중에 다시 살펴볼게” 라는 생각을 자주 하게 됩니다. 하지만 이런 미뤄진 고민이 쌓이면 결국 코드 품질 저하, 버그 증가, 팀 커뮤니케이션 비용 등 다양한 문제를 야기합니다. 이번 포스트에서는 인사이트 부채가 정확히 무엇인지, 왜 발생하는지, 그리고 초보...

Dec 29, 20253 min read

블록체인 활용: 일상 속 5가지 실생활 적용 사례와 시작 가이드

# 서론 – “블록체인, 우리 생활에 뭐가 바뀔까?” 최근 뉴스와 SNS에서 블록체인이라는 단어를 자주 보지만, 실제로 우리 주변에 어떻게 적용되고 있는지는 잘 모르는 경우가 많습니다. “복잡하고 비싸다”는 인식이 남아 있지만, 최근는 블록체인 활용이 점점 쉬워지고 비용도 낮아져 일반인도 직접 체험할 수 있는 시대가 왔습니다. 이번 글에서는 블록체인 적용 사례 5가지를 중심으로, 초보자도 바로 이해하고 시작할 수 있는 방법을 알려드립니다. #...

Dec 29, 20254 min read

스크래핑 온 더 엣지: SvelteKit으로 만든 초고속 만화 뷰어 만들기 (50자)

# 서론 – “만화 읽기가 이렇게 불편할 수 있을까?” 우리 모두가 한 번쯤 겪어본 일입니다. 만화를 읽고 싶을 땐 원하는 사이트가 로딩이 오래 걸리거나, 페이지를 넘길 때마다 광고가 끊임없이 뜨고, 이미지가 깨져서 눈이 피로해지는 경우가 있죠. 이런 불편함을 그냥 견뎌야 할까요? 개발자라면 “코드로 해결할 수 있지 않을까?” 하는 생각이 떠오릅니다. 이번 포스트에서는 SvelteKit과 웹 스크래핑을 활용해, 초고속 만화 뷰어를 직접 만드는 ...

Dec 29, 20254 min read

Tim van der Lippe가 Mockito 유지보수자를 떠나다 – Java 테스트 생태계에 미치는 영향은?

SEO 키워드: Mockito, Java 단위 테스트, 테스트 자동화 # 서론 – “왜 이 소식이 중요한가?” 최근 Reddit의 r/programming 커뮤니티에 올라온 글에서 Tim van der Lippe가 오랜 기간 담당해 온 Mockito 프로젝트의 유지보수자를 물러난다는 소식이 전해졌습니다. Mockito는 Java 개발자 사이에서 가장 널리 쓰이는 테스트 자동화 라이브러리 중 하나이며, 수많은 오픈소스 프로젝트와 기업 서비스의 ...

Dec 29, 20253 min read2
H

HA JIN-YOUNG's blog

967 posts