3D 그래픽스 면접 질문 모범답변 (게임 클라이언트 프로그래머용)
1. 렌더링 파이프라인
1. 렌더링 파이프라인 전체를 설명해주세요.
정점 데이터가 화면 픽셀이 되기까지의 처리 단계입니다. D3D11 기준으로 IA(정점/인덱스 조립) → VS(정점 변환) → [HS → Tessellator → DS](테셀레이션, 선택) → [GS](기하 생성, 선택) → Rasterizer(삼각형→픽셀 후보 변환, 고정 기능) → PS(픽셀 색 계산) → OM(깊이/스텐실 테스트, 블렌딩 후 렌더 타겟 기록) 순입니다. 큰 흐름으로 요약하면 “기하 처리(정점 단위) → 래스터화 → 픽셀 처리(픽셀 단위)“이고, 프로그래머블 단계(VS/PS 등)와 고정 기능 단계(IA/RS/OM)가 교차하는 구조입니다.
2. Input Assembler의 역할은 무엇인가요?
정점 버퍼와 인덱스 버퍼에서 데이터를 읽어, 지정된 토폴로지(삼각형 리스트 등)에 따라 프리미티브를 조립해 파이프라인에 공급하는 고정 기능 단계입니다. 이때 Input Layout이 “버퍼의 바이트 덩어리를 어떤 시맨틱(POSITION, NORMAL, UV)으로 해석할지”를 정의하며, 정점 셰이더의 입력 시그니처와 일치해야 합니다. 인덱스 버퍼를 쓰는 이유는 공유 정점의 중복 제거로 메모리와 정점 셰이더 실행 횟수(포스트 트랜스폼 캐시 활용)를 줄이기 위함입니다.
3. Vertex Shader의 역할은 무엇인가요?
정점 하나마다 실행되어 좌표 변환을 수행하는 프로그래머블 단계입니다. 핵심 임무는 로컬 좌표를 WVP 행렬로 곱해 클립 공간 좌표(SV_Position)를 출력하는 것이고, 부가적으로 법선 변환, UV 전달, 스키닝(본 행렬 팔레트로 정점 변형), 버텍스 애니메이션 등을 수행합니다. 정점을 생성하거나 제거할 수는 없고 1:1 변환만 가능하다는 제약이 있습니다.
4. Hull Shader와 Domain Shader의 역할은 무엇인가요?
테셀레이션(폴리곤 세분화) 파이프라인의 양 끝입니다. Hull Shader는 패치 단위로 실행되어 얼마나 잘게 나눌지(테셀레이션 팩터)를 결정하고, 고정 기능 Tessellator가 그 팩터대로 도메인을 분할해 새 정점 위치(바리센트릭 좌표)를 생성하면, Domain Shader가 그 좌표를 받아 실제 정점 위치를 계산합니다. 카메라와 가까울수록 촘촘하게 나누는 적응형 세분화가 가능해, 지형 디테일이나 디스플레이스먼트 매핑에 사용합니다.
5. Geometry Shader의 역할은 무엇인가요?
프리미티브(삼각형, 선, 점) 단위로 실행되어, 프리미티브를 통째로 받아 새 프리미티브를 생성·제거·변형할 수 있는 유일한 단계입니다. 점 하나를 카메라를 향한 사각형으로 확장하는 빌보드/파티클, 한 번의 드로우로 큐브맵 6면에 출력하는 것(SV_RenderTargetArrayIndex) 등이 대표 용도입니다. 다만 출력량이 가변적이라 GPU 병렬성과 궁합이 나빠 성능이 좋지 않은 것으로 알려져 있고, 요즘은 인스턴싱이나 컴퓨트 셰이더로 대체하는 추세입니다.
6. Rasterizer의 역할은 무엇인가요?
클립 공간의 프리미티브를 화면의 픽셀 후보(프래그먼트)들로 변환하는 고정 기능 단계입니다. 이 단계에서 원근 나눗셈, 뷰포트 변환, 클리핑, 백페이스 컬링이 수행되고, 삼각형이 덮는 픽셀들을 판정한 뒤 각 픽셀 위치에서 정점 속성(UV, 법선, 색)을 원근 보정 보간해 픽셀 셰이더에 전달합니다. “기하의 세계에서 픽셀의 세계로 넘어가는 관문”이라고 요약할 수 있습니다.
7. Pixel Shader의 역할은 무엇인가요?
래스터라이저가 만든 픽셀 후보마다 실행되어 최종 색을 계산하는 프로그래머블 단계입니다. 보간된 속성과 텍스처 샘플링, 조명 계산을 조합해 색(SV_Target)을 출력하며, 필요 시 깊이를 직접 출력하거나(SV_Depth, Early-Z 무효화 주의) clip/discard로 픽셀을 버릴 수 있습니다. 화면 해상도만큼 대량 실행되므로 렌더링 비용의 큰 비중을 차지하는 경우가 많고, 픽셀 병목 최적화의 주 대상입니다.
8. Output Merger의 역할은 무엇인가요?
픽셀 셰이더의 출력을 렌더 타겟에 최종 기록할지, 어떻게 기록할지 결정하는 고정 기능 단계입니다. 깊이 테스트(깊이 버퍼와 비교해 가려진 픽셀 폐기), 스텐실 테스트, 그리고 블렌딩(알파 블렌딩 등 기존 렌더 타겟 값과의 합성)을 수행합니다. 픽셀 간 순서와 원자성이 보장되는 지점이기도 해서, 반투명 정렬 문제나 블렌드 스테이트 설정이 모두 이 단계와 관련됩니다.
9. 고정 기능 단계와 프로그래머블 단계의 차이는 무엇인가요?
프로그래머블 단계(VS, HS, DS, GS, PS, CS)는 개발자가 HLSL로 동작을 직접 작성하는 단계이고, 고정 기능 단계(IA, Tessellator, RS, OM)는 하드웨어에 동작이 고정되어 있어 상태 설정(래스터라이저 스테이트, 블렌드 스테이트 등)으로만 제어하는 단계입니다. 고정 기능으로 남겨둔 이유는 래스터화나 블렌딩처럼 모든 렌더링이 공통으로 쓰는 정형화된 작업은 전용 하드웨어가 압도적으로 효율적이기 때문입니다. 즉 파이프라인은 “유연성이 필요한 곳은 셰이더, 정형화된 곳은 전용 하드웨어”로 설계된 구조입니다.
10. 드로우콜이 발생하면 GPU에서는 어떤 일이 일어나나요?
Draw 호출 자체는 CPU에서 커맨드 버퍼에 명령을 기록하는 것이고, 드라이버가 현재 바인딩된 상태(셰이더, 버퍼, 텍스처, 파이프라인 스테이트)를 검증·변환해 GPU 커맨드로 만듭니다. GPU는 커맨드 프로세서가 이를 읽어 정점 처리 웨이브를 스케줄링하고, IA→VS→RS→PS→OM 파이프라인을 병렬로 흘려보냅니다. 중요한 사실 두 가지는, CPU와 GPU가 비동기라 Draw 리턴 시점에 실제 그리기는 아직 안 됐을 수 있다는 것과, 드로우콜의 진짜 비용은 GPU 실행보다 CPU 쪽 드라이버 오버헤드(상태 검증·전환)인 경우가 많다는 것입니다. 이것이 제가 드로우콜 자체를 줄이는 최적화(13,000→1,800)에 집중했던 이유이기도 합니다.
11. CPU와 GPU의 작업 분담을 설명해주세요.
CPU는 게임 로직, 물리, AI, 컬링, 드로우콜 준비 등 분기가 많고 순차적인 작업을 담당하고, GPU는 정점 변환·픽셀 셰이딩처럼 동일 연산을 대량 데이터에 반복하는 작업을 담당합니다. 매 프레임 CPU가 “무엇을 어떻게 그릴지” 커맨드를 만들어 넘기면 GPU가 실행하는 생산자-소비자 관계이며, 보통 1~2프레임 지연을 두고 파이프라인처럼 겹쳐 돌아갑니다. 프레임 시간은 둘 중 느린 쪽이 결정하므로, 최적화의 첫 단계는 어느 쪽이 병목인지 측정으로 특정하는 것입니다.
12. GPU가 병렬 처리에 유리한 이유는 무엇인가요?
구조 자체가 처리량(throughput) 지향으로 설계됐기 때문입니다. CPU가 소수의 강력한 코어에 캐시·분기 예측·비순차 실행 같은 지연 감소 장치를 투자한다면, GPU는 그 공간에 수천 개의 단순한 ALU를 넣었습니다. 그래픽스 작업이 “모든 정점·픽셀에 같은 연산, 상호 의존성 없음”이라는 완벽한 병렬성을 갖기 때문입니다. 또한 메모리 지연을 캐시로 숨기는 대신, 대기 중인 스레드 그룹을 다른 그룹으로 즉시 교체하는 방식(대규모 하드웨어 스레딩)으로 숨깁니다.
13. GPU가 분기 처리에 불리한 이유는 무엇인가요?
GPU는 32~64개 스레드가 하나의 명령을 함께 실행하는 SIMT 구조라, 같은 웨이브 안에서 스레드들이 if의 서로 다른 방향으로 갈리면(divergence) 양쪽 경로를 모두 순차 실행하고 각 스레드는 자기 경로가 아닌 동안 마스킹되어 놀기 때문입니다. 최악의 경우 분기 양쪽 비용의 합이 되어 병렬 효율이 급감합니다. 그래서 셰이더에서는 인접 픽셀들이 같은 방향으로 갈리는 일관된(coherent) 분기는 괜찮지만, 픽셀마다 제각각 갈리는 분기는 피하고, lerp·step 같은 수식으로 분기를 대체하거나 머티리얼별로 셰이더를 분리하는 식으로 설계합니다.
14. SIMD와 SIMT를 설명해주세요.
둘 다 “하나의 명령으로 여러 데이터를 처리”하는 병렬화지만 단위가 다릅니다. SIMD는 한 스레드 안에서 넓은 레지스터(SSE 128비트, AVX 256비트)에 여러 데이터를 담아 한 명령으로 처리하는 방식으로, CPU에서 벡터·행렬 연산 가속에 쓰입니다(DirectXMath가 SSE 기반인 이유). SIMT는 GPU의 방식으로, 각자 레지스터와 상태를 가진 다수의 스레드가 그룹(워프/웨이브) 단위로 같은 명령을 동시에 실행합니다. SIMT는 스레드별로 분기가 가능하다는 유연성이 있지만, 갈리는 순간 성능이 떨어지는 것이 13번의 divergence 문제입니다.
2. 좌표 변환·투영
15. 모델 정점이 화면 픽셀이 되기까지 좌표 변환 과정을 설명해주세요.
로컬 공간 정점에 월드 행렬을 곱해 월드 공간으로(씬 배치), 뷰 행렬을 곱해 뷰 공간으로(카메라 기준), 투영 행렬을 곱해 클립 공간으로(절두체→표준 상자) 변환하는 것까지가 정점 셰이더의 일입니다. 이후 하드웨어가 클리핑을 수행하고, 원근 나눗셈(w로 나누기)으로 NDC를 만들고, 뷰포트 변환으로 NDC의 -11 범위를 실제 화면 픽셀 좌표와 01 깊이로 매핑합니다. 요약: 로컬 →(W)→ 월드 →(V)→ 뷰 →(P)→ 클립 →(÷w)→ NDC →(뷰포트)→ 화면.
16. 클립 공간은 무엇인가요?
투영 행렬을 곱한 직후, 원근 나눗셈을 하기 전의 동차 좌표 공간입니다. 이름 그대로 클리핑이 수행되는 공간으로, -w ≤ x,y ≤ w, 0 ≤ z ≤ w(DirectX 기준) 조건으로 절두체 안팎을 판정합니다. 나눗셈 전에 클리핑하는 이유는, w가 0에 가깝거나 음수인(카메라 뒤) 정점을 나눠버리면 좌표가 발산하거나 뒤집히기 때문에, 선형성이 유지되는 동차 좌표 상태에서 잘라내는 것이 안전하고 정확하기 때문입니다.
17. 클립 좌표의 w는 어떤 의미인가요?
원근 투영에서 w는 뷰 공간의 깊이(카메라로부터의 거리, z)입니다. 투영 행렬이 의도적으로 뷰 공간 z를 w 성분에 복사하도록 구성되어 있습니다. 이 w가 이후 원근 나눗셈의 분모가 되어 “멀수록 작게”를 만들고, 원근 보정 보간의 기준값이 되며, 클리핑의 경계값이 됩니다. 직교 투영에서는 w가 항상 1이라 나눗셈이 아무 효과가 없는 것이고, 이것이 직교 투영에 원근감이 없는 수학적 이유입니다.
18. Perspective Divide는 무엇인가요?
클립 좌표의 x, y, z를 w로 나누어 NDC를 만드는 고정 기능 단계입니다. w에는 뷰 공간 깊이가 들어 있으므로, 이 나눗셈이 곧 “거리로 나누기”이며 원근감(멀수록 화면 중앙으로 수렴하며 작아짐)이 실제로 만들어지는 순간입니다. 래스터라이저 내부에서 클리핑 후에 수행됩니다.
19. 왜 x, y, z를 w로 나누나요?
원근 투영의 본질이 “화면상 크기 ∝ 1/거리”라는 비선형 연산인데, 행렬 곱은 선형 연산이라 나눗셈을 직접 표현할 수 없기 때문입니다. 그래서 두 단계로 나눕니다. 행렬은 분모가 될 거리(z)를 w에 실어두는 것까지만 하고, 실제 나눗셈은 별도 단계로 미룹니다. 이렇게 하면 나눗셈 전까지는 모든 변환이 행렬 곱으로 유지되어 WVP를 하나로 합성할 수 있고, 클리핑도 선형 공간에서 안전하게 수행한 뒤 마지막에 원근을 적용할 수 있습니다. z까지 나누는 것은 깊이를 0~1 범위로 정규화해 깊이 버퍼에 기록하기 위함입니다.
20. NDC란 무엇인가요?
정규화 장치 좌표(Normalized Device Coordinates)로, 원근 나눗셈 후의 해상도 독립적인 표준 좌표계입니다. 어떤 해상도든 화면 전체가 같은 범위(x, y는 -1~1)로 표현되므로, 이후 뷰포트 변환 한 번으로 임의의 해상도·뷰포트에 매핑할 수 있습니다. 풀스크린 쿼드를 그릴 때 NDC 좌표를 직접 출력하는 것처럼, 포스트 프로세싱 셰이더 작성 시에도 직접 다루게 되는 공간입니다.
21. DirectX의 NDC 범위는 어떻게 되나요?
x, y는 -11이고, z(깊이)는 01입니다. y는 위쪽이 +1입니다. 참고로 텍스처 UV는 좌상단 (0,0) 기준으로 y가 아래로 증가하므로, NDC와 UV 간 변환 시 y 반전이 필요합니다(풀스크린 패스에서 흔한 실수 지점). OpenGL은 z까지 -1~1이라는 점이 대표적인 차이입니다.
22. OpenGL과 DirectX의 깊이 범위 차이는 무엇인가요?
DirectX는 NDC 깊이가 01, OpenGL은 전통적으로 -11입니다. 실무적 함의가 두 가지 있습니다. 첫째, 투영 행렬 공식이 서로 달라 수학 라이브러리(GLM 등)를 교차 사용할 때 규약을 확인해야 합니다. 둘째, 01 방식이 정밀도 면에서 유리합니다. -11은 부동소수점 정밀도가 높은 0 근처가 깊이 중간에 낭비되기 때문입니다. 그래서 OpenGL도 이후 01 모드(glClipControl)를 지원하게 되었고, Reversed-Z 최적화도 01 규약에서 효과가 극대화됩니다.
23. 뷰포트 변환은 무엇인가요?
NDC를 실제 렌더 타겟의 픽셀 좌표로 매핑하는 마지막 고정 변환입니다. x, y의 -11을 뷰포트의 (TopLeftX, TopLeftY, Width, Height) 사각형으로 스케일+이동하고(이때 y축 방향이 화면 좌표계에 맞게 뒤집힘), z의 01을 MinDepth~MaxDepth로 매핑합니다. 뷰포트를 렌더 타겟보다 작게 설정하면 화면 일부에만 그리는 것이 가능해, 분할 화면이나 미니맵 렌더링에 활용됩니다.
24. 깊이 값을 0~1로 정규화하는 이유는 무엇인가요?
깊이 버퍼가 유한 정밀도의 고정된 저장 형식이기 때문입니다. 뷰 공간 z는 nearfar로 씬마다 범위가 다른데, 이를 그대로 저장하면 버퍼 포맷이 씬에 종속됩니다. 01로 정규화하면 어떤 near/far 설정이든 동일한 포맷(24비트 정규화, 32비트 float)에 담을 수 있고, 하드웨어 깊이 테스트가 표준화된 범위에서 일관되게 동작할 수 있습니다. 클리핑 경계 판정(0 ≤ z ≤ w)이 단순해지는 것도 이점입니다.
25. 원근 투영 후 깊이 값이 비선형적인 이유는 무엇인가요?
깊이도 x, y와 함께 w(=뷰 공간 z)로 나눠지기 때문입니다. 투영 후 깊이는 (a·z + b) / z = a + b/z 형태로, 뷰 공간 거리 z에 대한 1/z 함수가 됩니다. 즉 NDC 깊이는 거리에 비례하지 않고, 가까운 구간에서 급격히 변하고 먼 구간에서는 거의 변하지 않습니다. 이 비선형성 때문에 깊이 버퍼 값으로 거리 비교 이상의 계산(안개, 재구성)을 하려면 뷰 공간 z로 역변환(선형화)이 필요합니다. 디퍼드 렌더링에서 깊이로 월드 위치를 복원할 때 실제로 다루게 되는 부분입니다.
26. 깊이 정밀도가 Near Plane 근처에 집중되는 이유는 무엇인가요?
25번의 1/z 곡선 때문입니다. 1/z는 z가 작을 때 기울기가 가파르고 클 때 완만하므로, near 근처의 좁은 거리 구간이 0~1 깊이 범위의 대부분을 차지하고, far까지의 광대한 구간이 나머지 좁은 범위에 압축됩니다. 예를 들어 near 0.1, far 1000이면 깊이 0.9까지가 카메라 앞 약 1m 이내에 소진되는 수준입니다. 여기에 부동소수점 자체도 0 근처 정밀도가 높아 편중이 이중으로 발생합니다. 그래서 near를 무심코 줄이는 것이 원거리 z-fighting의 주범이 되고, Reversed-Z가 이 이중 편중을 상쇄하는 해법이 됩니다.
27. Z-fighting이 발생하는 이유는 무엇인가요?
깊이가 거의 같은 두 표면의 깊이 버퍼 값이 유한 정밀도 때문에 구분되지 않아, 픽셀·프레임마다 깊이 테스트 승자가 뒤바뀌며 두 표면이 지글거리며 교차해 보이는 현상입니다. 근본 원인은 두 표면의 실제 깊이 차이가 해당 거리에서의 깊이 버퍼 표현 간격보다 작은 것이고, 26번의 정밀도 편중 때문에 카메라에서 멀수록 쉽게 발생합니다. 겹쳐 배치된 데칼·바닥면, 벽에 붙인 포스터 같은 코플래너 지오메트리가 전형적인 발생 지점입니다.
28. Z-fighting을 줄이는 방법은 무엇인가요?
원인별로 접근합니다. ① near plane을 최대한 키우고 far를 줄여 정밀도 낭비를 줄입니다(가장 효과 큼). ② 32비트 float 깊이 버퍼 + Reversed-Z로 정밀도 분포를 개선합니다. ③ 코플래너 지오메트리에는 래스터라이저의 Depth Bias(폴리곤 오프셋)를 적용하거나, 애초에 지오메트리를 미세하게 띄워 모델링합니다. ④ 데칼은 깊이 테스트 방식 자체를 바꿔(프로젝션 데칼) 해결합니다. 실무에서는 “일단 near 값부터 확인”이 정석 순서입니다.
29. Reverse-Z란 무엇인가요?
깊이 매핑을 뒤집어 near를 1, far를 0에 대응시키는 기법입니다. 구현은 투영 행렬의 깊이 항을 뒤집고, 깊이 테스트 비교 함수를 LESS에서 GREATER로, 클리어 값을 1에서 0으로 바꾸면 됩니다. 32비트 float 깊이 버퍼와 함께 사용해야 효과가 있으며, 최신 엔진들이 표준으로 채택한 사실상의 공짜 정밀도 개선 기법입니다.
30. Reverse-Z가 깊이 정밀도를 개선하는 이유는 무엇인가요?
두 개의 정밀도 편중을 서로 상쇄시키기 때문입니다. 원근 투영의 1/z 매핑은 near 쪽에 깊이 값을 몰아주고(far 쪽이 정밀도 부족), 부동소수점은 0 근처에 표현 가능한 값이 몰려 있습니다(1 근처가 성김). 일반 매핑은 near→0, far→1이라 “이미 유리한 near에 float 정밀도까지 몰아주는” 이중 낭비인데, 뒤집으면 far→0이 되어 1/z 때문에 정밀도가 부족했던 원거리에 float의 촘촘한 구간이 배정됩니다. 결과적으로 깊이 표현 간격이 전 거리에 걸쳐 훨씬 균등해져, 원거리 z-fighting이 극적으로 줄어듭니다.
3. 래스터라이징·보간
31. 삼각형이 래스터라이징되는 과정을 설명해주세요.
원근 나눗셈과 뷰포트 변환을 거친 삼각형에 대해, ① 세 정점의 화면 좌표로 바운딩 영역을 잡고, ② 그 영역의 픽셀들(정확히는 2×2 쿼드 단위)에 대해 커버리지 테스트, 즉 픽셀 중심이 삼각형 세 변의 안쪽에 있는지를 에지 함수로 판정합니다. ③ 덮인 픽셀마다 바리센트릭 좌표를 계산해 정점 속성을 원근 보정 보간하고, ④ 그 결과를 픽셀 셰이더 입력으로 전달합니다. 2×2 쿼드 단위로 처리하는 이유는 텍스처 밉맵 선택에 필요한 UV 미분값(ddx/ddy)을 인접 픽셀 차이로 구하기 위해서이며, 이 때문에 아주 작은 삼각형은 실제 커버 픽셀보다 많은 셰이더 실행을 유발해 비효율적입니다(쿼드 오버셰이딩).
32. 백페이스 컬링이란 무엇인가요?
카메라를 등지고 있는 삼각형을 래스터라이저 단계에서 폐기하는 최적화입니다. 닫힌 불투명 메시는 뒷면이 어차피 앞면에 가려지므로, 그리기 전에 버리면 픽셀 셰이딩 비용을 절반 가까이 절약할 수 있습니다. 판정은 화면 공간에서 삼각형 정점의 감김 방향(winding)이 시계인지 반시계인지로 합니다. 안팎이 모두 보여야 하는 지오메트리(풀잎, 천, 열린 메시)는 컬링을 끄거나 양면 렌더링으로 처리합니다.
33. winding order란 무엇인가요?
삼각형 세 정점의 나열 순서가 화면에서 시계 방향(CW)인지 반시계 방향(CCW)인지를 뜻하며, 이것이 삼각형의 앞면 정의가 됩니다. DirectX 기본은 CW가 앞면, OpenGL 기본은 CCW가 앞면입니다. 실무에서 마주치는 지점은 두 가지입니다. 다른 좌표계의 툴에서 익스포트한 모델은 와인딩이 반대라 앞뒤가 뒤집혀 보이며(모델 로더에서 인덱스 순서를 뒤집어 해결한 경험이 있습니다), 스케일에 음수(미러링)가 들어가면 와인딩이 뒤집혀 컬링이 반대로 됩니다.
34. 바리센트릭 좌표는 무엇인가요?
삼각형 내부의 점을 세 정점의 가중 평균으로 표현하는 좌표 (α, β, γ)입니다. α+β+γ=1이고, 각 값은 해당 정점 맞은편 부분 삼각형의 넓이 비율에 해당합니다. 정점에서는 (1,0,0) 형태, 무게중심에서는 (⅓,⅓,⅓)이 됩니다. 래스터라이저가 픽셀마다 이 좌표를 계산하고, 정점 속성 보간이 attr = α·A + β·B + γ·C로 수행됩니다. 레이-삼각형 교차 판정에서 명중 지점의 UV를 구할 때도 같은 좌표를 사용합니다.
35. 정점 속성은 픽셀까지 어떻게 보간되나요?
정점 셰이더가 출력한 속성(UV, 법선, 색 등)을 래스터라이저가 각 픽셀의 바리센트릭 좌표로 가중 평균해 픽셀 셰이더에 전달합니다. 이때 화면 공간에서의 단순 선형 보간이 아니라, 각 속성을 정점의 w로 나눈 값(attr/w)과 1/w을 선형 보간한 뒤 픽셀에서 다시 나누어 복원하는 원근 보정 보간을 수행합니다. HLSL에서는 보간 방식을 시맨틱 지정자(linear, noperspective, nointerpolation/flat, centroid)로 제어할 수도 있습니다.
36. Perspective Correct Interpolation이 필요한 이유는 무엇인가요?
원근 투영이 비선형이라, 3D 공간에서 등간격인 것이 화면 공간에서는 등간격이 아니기 때문입니다. 기울어진 삼각형에서 화면상 중간 픽셀은 3D 상으로는 중간이 아니라 카메라 쪽으로 치우친 지점입니다. 이를 무시하고 화면 공간에서 UV를 선형 보간하면, 바닥 텍스처가 거리에 따라 휘어지고 미끄러지는 왜곡(초기 PS1 게임의 텍스처 흔들림이 유명한 사례)이 생깁니다. 해결 원리는 “attr/w는 화면 공간에서 선형”이라는 성질을 이용해, attr/w와 1/w를 보간한 뒤 픽셀에서 (attr/w)÷(1/w)로 복원하는 것이고, 현대 GPU는 이를 하드웨어로 자동 수행합니다.
37. Early-Z란 무엇인가요?
깊이 테스트를 픽셀 셰이더 실행 전에 수행해, 어차피 가려질 픽셀의 셰이딩 자체를 건너뛰는 하드웨어 최적화입니다. 원래 규격상 깊이 테스트는 OM(셰이더 후) 단계지만, 셰이더가 깊이를 바꾸지 않는다면 결과가 동일하므로 GPU가 앞당겨 수행합니다. 효과를 보려면 조건이 필요한데, 불투명 오브젝트를 앞→뒤 순서로 정렬해 그려야 뒤쪽 픽셀들이 조기 탈락합니다. 셰이더에서 SV_Depth 출력이나 discard를 쓰면 결과가 달라질 수 있어 하드웨어가 Early-Z를 비활성화한다는 점도 중요합니다. 저는 렌더링 패킷 정렬 단계에서 불투명 오브젝트의 앞→뒤 정렬로 이 하드웨어 최적화를 활용했습니다.
38. 오버드로우란 무엇인가요?
한 픽셀이 한 프레임에 여러 번 그려지는(셰이딩되는) 것입니다. 뒤쪽 물체를 그린 뒤 앞쪽 물체가 덮어쓰면 뒤쪽 셰이딩은 낭비가 되고, 반투명 파티클이 겹겹이 쌓이는 경우가 최악의 사례입니다. 픽셀 셰이더 비용 × 오버드로우 배수만큼 GPU 시간이 늘어나므로 Fill Rate 병목의 주원인입니다. 대응책은 불투명은 앞→뒤 정렬 + Early-Z로 낭비를 차단하고, 반투명은 파티클 크기·겹침을 줄이거나 저해상도 버퍼에 그린 뒤 업샘플링하는 것입니다. 디퍼드 렌더링 역시 “조명 계산의 오버드로우를 G-Buffer로 차단하는” 구조적 해법이라 할 수 있습니다.
39. 알파 블렌딩 객체에서 Early-Z가 제한되는 이유는 무엇인가요?
반투명은 뒤가 비쳐 보여야 하므로 “가려지면 버린다”는 전제 자체가 성립하지 않기 때문입니다. 올바른 블렌딩을 위해 반투명은 뒤→앞 순서로 그려야 하는데, 이는 Early-Z가 효과를 내는 앞→뒤 정렬과 정반대라 조기 탈락이 거의 일어나지 않습니다. 또한 반투명 픽셀은 깊이를 기록하지 않는 것이 일반적이라(기록하면 뒤에 그려질 반투명이 잘림) 깊이 버퍼로 뒤 픽셀을 걸러주는 효과도 없습니다. 알파 테스트(clip/discard) 계열도 셰이더 실행 전에는 폐기 여부를 알 수 없어 Early-Z가 제한됩니다. 그래서 렌더 패스를 불투명(앞→뒤) → 반투명(뒤→앞)으로 분리하는 것이 표준 구조입니다.
4. 텍스처·색상
40. 텍스처 좌표 UV란 무엇인가요?
텍스처 위의 위치를 해상도와 무관하게 0~1로 정규화해 나타내는 2차원 좌표입니다(DirectX는 좌상단이 (0,0), v가 아래로 증가). 모델링 단계에서 각 정점에 UV를 할당하는 것(UV 언래핑)은 3D 표면을 2D 텍스처에 펼쳐 대응시키는 작업이고, 런타임에는 정점 UV가 픽셀까지 보간되어 그 좌표로 텍스처를 샘플링해 표면 무늬가 입혀집니다.
41. 텍스처 샘플링은 어떻게 이루어지나요?
픽셀 셰이더에서 SRV로 바인딩된 텍스처를 샘플러 스테이트와 함께 Sample 계열 함수로 읽는 것입니다. 하드웨어 텍스처 유닛이 ① UV를 어드레싱 모드(wrap/clamp 등)로 처리하고, ② UV의 화면 공간 변화율(ddx/ddy)로 적절한 밉 레벨을 선택하고, ③ 필터링 모드에 따라 주변 텍셀들을 읽어 가중 평균한 값을 반환합니다. 즉 샘플링은 단순 배열 읽기가 아니라 어드레싱+밉 선택+필터링이 결합된 하드웨어 연산이며, 텍스처(데이터)와 샘플러(읽는 방법)가 분리되어 있다는 것이 D3D11 리소스 모델의 특징입니다.
42. Point, Bilinear, Trilinear 필터링의 차이는 무엇인가요?
Point는 가장 가까운 텍셀 1개를 그대로 읽는 방식으로, 가장 싸지만 확대 시 픽셀이 각지고 이동 시 지글거립니다(도트 게임에는 오히려 의도적으로 사용). Bilinear는 주변 4텍셀을 거리 가중 평균해 부드럽게 만들지만, 밉 레벨이 바뀌는 경계에서 선명도가 뚝 끊기는 줄이 보입니다. Trilinear는 인접한 두 밉 레벨에서 각각 bilinear한 결과를 다시 보간(총 8텍셀)해 밉 전환까지 매끄럽게 만듭니다. 비용은 Point < Bilinear < Trilinear 순이며, 경사면 흐림 문제는 남아 있어 Anisotropic이 그 다음 단계가 됩니다.
43. Mipmap을 사용하는 이유는 무엇인가요?
텍스처를 절반씩 줄인 축소 사본 체인을 미리 만들어두고, 화면에서 차지하는 크기에 맞는 레벨을 골라 샘플링하기 위해서입니다. 목적은 두 가지입니다. 첫째, 앨리어싱 방지입니다. 멀리 있는 표면은 픽셀 하나에 수많은 텍셀이 대응되는데, 그중 1~4개만 샘플링하면 프레임마다 다른 텍셀이 걸려 지글거립니다. 밉맵은 그 텍셀들의 평균을 미리 계산해둔 것이라 결과가 안정됩니다. 둘째, 성능입니다. 작은 밉을 읽으면 인접 픽셀들의 샘플 위치가 메모리상 가까워져 텍스처 캐시 적중률이 크게 오릅니다. 메모리 33% 추가라는 비용 대비 효과가 압도적이라 3D에서는 사실상 필수입니다.
44. Mipmap의 단점은 무엇인가요?
① 메모리가 약 33% 증가합니다. ② 과도한 흐림입니다. 특히 비스듬히 보는 표면(바닥, 도로)은 UV 변화율이 축마다 다른데, 밉 선택이 큰 쪽 기준으로 되어 필요 이상으로 낮은 해상도가 선택되어 뿌옇게 보입니다(Anisotropic 필터링으로 보완). ③ 밉 경계가 눈에 띌 수 있고(trilinear로 보완), ④ 텍스처 아틀라스에서는 낮은 밉에서 인접 영역의 색이 섞여 번지는(bleeding) 문제가 있어 패딩이 필요합니다.
45. Anisotropic Filtering은 무엇인가요?
비스듬히 보이는 표면을 위해, 시야각에 따라 늘어난 타원형 영역을 따라 여러 샘플을 찍어 평균하는 필터링입니다. trilinear까지는 샘플 영역을 정사각형으로 가정해 경사면에서 과하게 흐려지는데, anisotropic은 UV 변화율이 큰 축 방향으로 최대 16회까지 추가 샘플링해 경사면의 선명도를 유지합니다. 바닥·도로 텍스처 품질에 체감 효과가 가장 크고, 비용이 늘지만 현대 GPU에서는 부담이 크지 않아 8x~16x가 보편적인 기본 옵션입니다.
46. 텍스처 어드레싱 모드에는 무엇이 있나요?
UV가 0~1 범위를 벗어났을 때의 처리 규칙입니다. Wrap(반복)은 소수부만 취해 타일링하는 방식으로 바닥·벽 반복 텍스처에 쓰고, Mirror는 반복하되 매번 뒤집어 이음새를 감춥니다. Clamp는 경계 텍셀을 그대로 늘려 가장자리 번짐을 막는 방식으로 UI, 스카이박스, 포스트 프로세싱용 렌더 타겟 샘플링에 필수적입니다. Border는 범위 밖을 지정한 단색으로 채우며, 섀도우 맵 범위 밖을 “그림자 없음”으로 처리할 때 유용합니다. 렌더 타겟을 wrap으로 샘플링해 화면 반대편 색이 가장자리에 새어 들어오는 것이 전형적인 설정 실수입니다.
47. sRGB와 Linear 색 공간의 차이는 무엇인가요?
Linear는 수치가 물리적 빛의 양에 비례하는 공간으로, 조명·블렌딩 등 모든 수학적 색 연산이 올바르게 성립하는 공간입니다. sRGB는 인간 지각(어두운 영역에 민감)에 맞춰 감마 곡선으로 인코딩된 저장·표시용 공간으로, 8비트의 한정된 정밀도를 어두운 영역에 더 배분하기 위한 포맷입니다. 원칙은 “저장과 출력은 sRGB, 계산은 Linear”입니다. 디퓨즈 텍스처는 sRGB로 저장된 것이므로 샘플링 시 Linear로 변환해(SRGB 포맷 뷰 사용 시 하드웨어 자동) 조명 계산을 하고, 최종 출력 때 다시 sRGB로 인코딩합니다. 법선 맵·마스크·러프니스 같은 데이터 텍스처는 색이 아니므로 sRGB 변환을 하면 안 됩니다.
48. 감마 보정이 필요한 이유는 무엇인가요?
역사적으로 디스플레이가 입력 신호에 감마 곡선(대략 2.2제곱)을 적용해 출력하고, 콘텐츠는 그것을 상쇄하도록 미리 역감마로 인코딩되어(sRGB) 있기 때문입니다. 렌더러 입장에서 문제는, sRGB로 인코딩된 값을 선형인 줄 알고 조명 계산을 하면 결과가 물리적으로 틀린다는 것입니다. 증상으로는 중간 밝기가 실제보다 어둡게 보이고, 라이트가 겹치면 과하게 타버리며, 색 블렌딩 결과가 탁해집니다. 그래서 파이프라인 전체를 “입력 sRGB → 선형화 → 선형 공간에서 라이팅/블렌딩 → 출력 시 감마 인코딩”으로 일관되게 유지하는 것이 감마 보정이며, PBR의 전제 조건이기도 합니다.
49. 노멀 맵은 어떻게 동작하나요?
표면의 미세 요철을 지오메트리가 아니라 텍스처에 저장한 법선 방향으로 표현하는 기법입니다. 텍셀마다 법선 벡터(x,y,z)를 RGB에 인코딩해두고([-1,1]→[0,1]로 매핑되어 있어 샘플 후 ×2-1로 복원), 픽셀 셰이더에서 이 법선으로 조명을 계산하면 실제 폴리곤은 평평해도 빛이 요철에 반응하는 것처럼 보입니다. 저장된 법선은 보통 탄젠트 공간 기준이므로, TBN 행렬로 월드 공간으로 변환한 뒤 라이팅에 사용합니다. 정점 수를 늘리지 않고 디테일을 얻는 대표적인 비용 절감 기법이며, 하이폴리 모델을 로우폴리에 베이크하는 제작 파이프라인과 연결됩니다.
50. 탄젠트 공간이란 무엇인가요?
표면 위의 한 점을 기준으로 한 로컬 좌표계로, 법선 N(표면 수직), 탄젠트 T(UV의 u 증가 방향), 바이탄젠트 B(v 방향)의 세 축으로 구성됩니다. 노멀 맵을 이 공간 기준으로 저장하는 이유는 재사용성 때문입니다. “표면에서 어느 쪽으로 기울었는가”라는 상대적 정보만 담으므로, 같은 노멀 맵을 어떤 방향의 표면·어떤 모델에든 붙일 수 있고 애니메이션으로 표면이 변형돼도 유효합니다(오브젝트 공간 노멀 맵은 이것이 안 됨). 렌더링 시에는 정점의 T, B, N으로 TBN 행렬을 만들어 샘플링한 법선을 월드 공간으로 변환합니다. 탄젠트 공간 노멀 맵이 푸르스름한 이유는 대부분의 법선이 z(N)축 근처를 향해 B 채널 값이 크기 때문입니다.
51. 압축 텍스처 BC 포맷을 사용하는 이유는 무엇인가요?
GPU가 샘플링 시점에 하드웨어로 직해제할 수 있는 블록 압축 포맷이라, VRAM 사용량과 메모리 대역폭을 그대로 1/4~1/8로 줄일 수 있기 때문입니다. 4×4 텍셀 블록마다 대표색 2개와 보간 인덱스를 저장하는 방식이며, PNG/JPG처럼 통째로 풀어야 하는 포맷과 달리 압축된 채로 VRAM에 상주하고 임의 접근이 가능하다는 것이 본질적 차이입니다. 용도별로 BC1(불투명 컬러, 1/8), BC3(알파 포함), BC4/BC5(단채널/2채널, 노멀 맵은 BC5에 xy만 담고 z 재구성), BC7(고품질 컬러)을 구분해 씁니다. 손실 압축이므로 그라데이션 밴딩 등 아티팩트 가능성은 있지만, 대역폭 절감이 곧 성능이라 실무에서는 비압축 텍스처가 예외에 속합니다.
5. 조명
52. Ambient, Diffuse, Specular를 설명해주세요.
고전 조명 모델에서 표면 밝기를 세 성분의 합으로 근사한 것입니다. Ambient는 간접광의 대체물로, 방향과 무관하게 일정하게 더해 완전한 암흑을 막는 상수항입니다. Diffuse는 거친 표면에서 빛이 모든 방향으로 고르게 산란되는 성분으로, 표면이 빛을 얼마나 정면으로 받는지(N·L)에 비례하며 보는 각도와 무관합니다. Specular는 매끈한 표면의 정반사 하이라이트로, 반사 방향과 시선의 정렬 정도에 따라 좁게 빛나며 시점에 따라 움직입니다. 최종 색 = Ambient + Diffuse + Specular가 고전 셰이딩의 골격이고, PBR은 이 구분을 물리 기반(알베도, 금속성, 거칠기)으로 재정의한 것입니다.
53. Lambert 조명 모델을 설명해주세요.
디퓨즈 반사를 N·L로 계산하는 가장 기본적인 모델입니다. Diffuse = albedo × lightColor × max(0, dot(N, L))로, N은 표면 법선, L은 표면에서 광원을 향한 단위 벡터입니다. 물리적 근거는 빛이 표면에 비스듬히 들어올수록 같은 양의 빛이 넓은 면적에 퍼져 단위 면적당 에너지가 cosθ로 줄어든다는 것입니다. max(0, ·)는 빛을 등진 면이 음수 조명을 받지 않게 하는 클램프입니다. 완전히 거친 표면(모든 방향 균등 산란)을 가정하므로 시선 방향이 수식에 없다는 것이 특징이며, half-Lambert처럼 어두운 면을 완화한 변형은 비사실적(NPR) 셰이딩에서 자주 쓰입니다.
54. Phong과 Blinn-Phong의 차이는 무엇인가요?
스페큘러 하이라이트 계산 방식의 차이입니다. Phong은 반사 벡터 R = reflect(-L, N)을 구해 시선 V와의 정렬도 (R·V)^n을 쓰고, Blinn-Phong은 L과 V의 중간 벡터 H = normalize(L+V)를 구해 (N·H)^n을 씁니다. Blinn-Phong이 표준이 된 이유는 ① reflect 계산보다 하프 벡터가 저렴하고, ② 시선과 광원이 스치는 각도(grazing angle)에서 Phong의 하이라이트가 부자연스럽게 잘리는 문제가 없으며, ③ 실측 반사 분포에 더 가깝기 때문입니다. 하이라이트 모양은 Blinn-Phong이 약간 더 퍼지므로 같은 느낌을 내려면 지수 n을 더 크게 줍니다. PBR의 법선 분포 함수(NDF)도 N·H 기반이라, Blinn-Phong은 PBR로 가는 개념적 징검다리이기도 합니다.
55. Normal Vector가 조명 계산에 필요한 이유는 무엇인가요?
표면이 빛을 받는 양과 반사하는 방향이 전적으로 표면의 방향에 의해 결정되는데, 그 방향을 나타내는 것이 법선이기 때문입니다. 디퓨즈의 N·L, 스페큘러의 반사/하프 벡터 계산, 프레넬의 시야각 계산까지 모든 조명 항이 법선을 입력으로 가집니다. 실무 주의점으로, 법선은 위치와 다르게 변환해야 합니다. 비균등 스케일이 있는 월드 행렬을 그대로 곱하면 법선이 표면과 수직이 아니게 되므로 역전치 행렬을 사용하고, 보간을 거친 픽셀 단계에서는 길이가 1이 아니게 되므로 재정규화가 필요합니다.
56. 점광원, 방향광, 스포트라이트의 차이는 무엇인가요?
방향광(Directional)은 무한히 먼 광원의 근사로, 위치 없이 방향만 있고 감쇠도 없어 씬 전체에 균일한 평행광을 비춥니다(태양). L 벡터가 상수라 가장 저렴합니다. 점광원(Point)은 위치에서 전방향으로 퍼지는 빛으로, 픽셀마다 L = lightPos - worldPos를 계산하고 거리 감쇠가 적용됩니다(전구, 폭발). 스포트라이트(Spot)는 점광원에 원뿔 각도 제한을 더한 것으로, 광원 방향과 L의 내적을 내부/외부 원뿔 각과 비교해 가장자리를 부드럽게 잘라냅니다(손전등, 무대 조명). 그림자 구현도 각각 달라서 방향광은 직교 투영(+CSM), 점광원은 큐브맵 6면, 스포트는 원근 투영 1장을 사용합니다.
57. 감쇠를 어떻게 계산하나요?
물리 법칙은 역제곱(1/d²)입니다. 빛이 구면으로 퍼지므로 단위 면적당 에너지가 거리 제곱에 반비례합니다. 다만 순수 역제곱은 광원 근처에서 발산하고 값이 0에 도달하지 않아 라이트 범위를 잘라낼 수 없으므로, 실무에서는 변형해 씁니다. 고전 방식은 1/(a + b·d + c·d²)로 상수·선형·제곱 항을 조절하는 것이고, 현대 방식은 역제곱을 기반으로 하되 분모에 작은 값을 더해 발산을 막고, 지정 반경에서 정확히 0이 되도록 부드러운 윈도우 함수를 곱하는 것입니다. 반경에서 0이 되게 만드는 이유는 디퍼드 렌더링의 라이트 볼륨처럼 “이 라이트가 영향을 주는 픽셀”을 명확히 한정해 계산을 스킵하기 위해서입니다.
58. PBR이란 무엇인가요?
물리 기반 렌더링(Physically Based Rendering)으로, 조명을 임의의 보기 좋은 수식이 아니라 물리 법칙(에너지 보존, 프레넬, 미세면 이론)에 기반해 계산하는 접근입니다. 핵심 원칙은 ① 에너지 보존(반사광이 입사광을 초과하지 않고, 스페큘러가 강해지면 디퓨즈가 줄어듦), ② 프레넬(모든 물질은 스치는 각도에서 반사율 급증), ③ 미세면 이론(거칠기를 미세한 거울면들의 방향 분포로 모델링)입니다. 실용적 가치는 재질 파라미터(알베도, Metallic, Roughness)가 물리량이라 어떤 조명 환경에서도 일관된 결과가 나온다는 것으로, 아티스트 워크플로우가 표준화됩니다. 자체 엔진에서는 Blinn-Phong 기반까지 구현했고, PBR은 미세면 BRDF(Cook-Torrance) 이론을 학습하며 다음 확장 목표로 준비하고 있습니다.
59. Metallic과 Roughness의 의미는 무엇인가요?
PBR 재질의 두 핵심 파라미터입니다. Metallic은 금속/비금속의 구분(01)으로, 비금속은 빛 일부가 표면 아래로 산란되어 나와 알베도 색의 디퓨즈가 있고 정반사는 약한 무채색(F0 약 4%)인 반면, 금속은 디퓨즈가 없고 정반사가 강하며 반사광 자체가 금속 고유색(금의 노란 반사)을 띱니다. 그래서 metallic이 1이면 알베도가 디퓨즈 색이 아니라 반사색(F0)으로 해석됩니다. Roughness는 미세면의 거칠기(01)로, 낮으면 미세면 방향이 정렬되어 거울 같은 선명한 반사, 높으면 방향이 흩어져 넓고 흐린 하이라이트가 됩니다. 이 두 값이 직관적이고 물리적으로 의미가 명확해 아티스트 친화적인 표준 워크플로우(Metallic-Roughness)가 되었습니다.
60. BRDF란 무엇인가요?
양방향 반사 분포 함수(Bidirectional Reflectance Distribution Function)로, “특정 방향에서 들어온 빛이 특정 방향으로 얼마나 반사되는가”를 정의하는 함수 f(l, v)입니다. 재질의 반사 특성을 수학적으로 완전히 기술하는 것이며, Lambert는 상수 BRDF, Blinn-Phong도 단순한 BRDF의 일종입니다. PBR 표준인 Cook-Torrance 스페큘러 BRDF는 D·F·G / (4(N·L)(N·V)) 구조로, D(법선 분포 함수: 거칠기에 따른 미세면 방향 분포), F(프레넬: 각도에 따른 반사율), G(기하 감쇠: 미세면끼리의 가림)의 세 항으로 구성됩니다. 렌더링 방정식에서 조명 적분의 커널에 해당하는 것이 BRDF라고 정리할 수 있습니다.
61. 그림자 맵은 어떻게 동작하나요?
“광원에서 보이지 않는 곳이 그림자”라는 원리를 2패스로 구현합니다. 1패스에서 카메라를 광원 위치에 놓고 씬의 깊이만 렌더링해 섀도우 맵(광원 기준 최근접 깊이)을 만듭니다. 2패스(본 렌더링)에서 각 픽셀의 월드 위치를 광원의 뷰·투영 행렬로 변환해 섀도우 맵의 대응 좌표와 깊이를 구하고, 저장된 깊이보다 내 깊이가 더 멀면 “광원과 나 사이에 무언가 있다” 즉 그림자로 판정합니다. 해상도가 유한한 깊이 버퍼 비교라는 본질 때문에 acne, 앨리어싱, 범위 문제 등이 파생되며, bias·PCF·CSM이 그 대응책들입니다. 자체 엔진에서 섀도우 맵을 직접 구현하며 이 파생 문제들을 하나씩 겪고 해결해본 경험이 있습니다.
62. Shadow Acne와 Peter Panning은 무엇인가요?
섀도우 맵의 정밀도 문제와 그 과잉 교정입니다. Shadow Acne는 표면이 자기 자신의 그림자로 얼룩덜룩해지는 현상으로, 섀도우 맵의 한 텍셀이 실제 표면의 일정 면적을 대표하다 보니 깊이 비교에서 같은 표면인데도 미세하게 “더 멀다”로 판정되는 자기 그림자(self-shadowing) 오차가 원인입니다. 해결은 비교 시 깊이에 bias를 더해 여유를 주는 것인데, bias가 과하면 이번엔 물체와 그림자가 접점에서 분리되어 그림자가 떠 보이는 Peter Panning이 생깁니다. 즉 둘은 bias 튜닝의 양극단이며, 표면 기울기에 비례해 bias를 주는 slope-scaled bias, 섀도우 패스에서 뒷면을 렌더링하는 기법 등으로 절충합니다.
63. PCF는 무엇인가요?
Percentage Closer Filtering으로, 섀도우 맵의 계단식 가장자리를 부드럽게 만드는 필터링입니다. 핵심은 깊이 값을 평균한 뒤 비교하는 게 아니라(깊이 평균은 무의미), 주변 텍셀들 각각에 대해 그림자 판정을 먼저 하고 그 결과(0/1)들을 평균해 “몇 %가 그림자인가”를 얻는 것입니다. 3×3, 5×5 등의 커널로 샘플링하며, 하드웨어 비교 샘플러(SampleCmp)를 쓰면 한 번에 2×2 비교+보간을 수행해 효율적입니다. 커널이 클수록 부드럽지만 비용이 늘고, 어디서나 균일하게 흐려질 뿐 실제 반그림자(광원에서 멀수록 흐려짐)는 아니므로, 그것까지 흉내 내는 것이 PCSS 같은 상위 기법입니다.
64. Cascaded Shadow Map은 무엇인가요?
방향광(태양) 그림자를 위해 시야 절두체를 거리별 구간(캐스케이드)으로 나누고, 구간마다 별도의 섀도우 맵을 할당하는 기법입니다. 넓은 야외 씬 전체를 한 장에 담으면 텍셀당 커버 면적이 너무 커져 근거리 그림자가 뭉개지는데, 근거리 구간에는 좁은 영역을 고해상도로, 원거리 구간에는 넓은 영역을 저해상도로 배정하면 “가까운 곳은 선명하게, 먼 곳은 적당히”라는 지각적 요구와 정밀도 배분이 일치하게 됩니다. 픽셀 셰이더에서는 픽셀의 깊이로 소속 캐스케이드를 선택해 해당 맵을 샘플링하며, 구간 경계에서 그림자 품질이 뚝 바뀌는 것을 감추기 위해 경계 블렌딩을 적용합니다. 오픈월드류 게임의 사실상 표준 그림자 기법입니다.
6. 렌더링 방식·최적화
65. 포워드 렌더링과 디퍼드 렌더링의 차이는 무엇인가요?
조명 계산 시점의 차이입니다. 포워드는 오브젝트를 그리는 그 자리에서 픽셀마다 모든 관련 라이트를 계산하므로, 비용이 대략 오브젝트 픽셀 수 × 라이트 수로 늘어나고 오버드로우된 픽셀의 조명 계산이 낭비됩니다. 디퍼드는 1패스에서 조명 없이 지오메트리의 표면 정보(알베도, 법선, 깊이 등)만 G-Buffer에 기록하고, 2패스에서 화면 픽셀마다 한 번씩만 조명을 계산합니다. 조명 비용이 “화면 픽셀 수 × 그 픽셀에 닿는 라이트”로 바뀌어 다수의 동적 라이트에 강한 대신, G-Buffer 메모리·대역폭 비용, 반투명 처리 불가, MSAA 곤란, 머티리얼 다양성 제약이라는 대가가 있습니다. 제 엔진은 다수 광원 씬을 목표로 디퍼드를 기본으로 하고, 반투명은 포워드 패스로 분리한 하이브리드 구조였습니다.
66. 디퍼드 렌더링의 G-Buffer에는 어떤 정보가 들어가나요?
조명 계산에 필요한 픽셀별 표면 정보입니다. 일반적으로 ① 알베도(기본색), ② 월드/뷰 공간 법선, ③ 재질 파라미터(스페큘러 파워 또는 PBR이면 Metallic/Roughness/AO), ④ 깊이(깊이 버퍼 재활용, 이것으로 월드 위치를 역산하므로 위치를 따로 저장하지 않는 것이 대역폭 절약의 정석)를 MRT(다중 렌더 타겟)로 동시 기록합니다. G-Buffer 설계의 본질은 대역폭과의 싸움이라, 법선을 2채널로 인코딩(octahedral)하거나 채널을 알뜰하게 패킹하는 것이 실무 포인트입니다. 제 엔진에서는 알베도, 법선, 깊이, 재질 정보 구성의 MRT로 설계했고, 라이팅 패스에서 깊이로부터 월드 위치를 복원하는 방식을 사용했습니다.
67. 디퍼드 렌더링에서 투명 객체 처리가 어려운 이유는 무엇인가요?
G-Buffer가 픽셀당 표면 하나의 정보만 저장할 수 있기 때문입니다. 반투명은 한 픽셀에 여러 표면이 겹쳐 보이는 것이 본질인데, G-Buffer에는 가장 앞 표면 하나만 남으므로 뒤에 비치는 표면들의 정보가 소실되어 블렌딩 자체가 불가능합니다. 그래서 표준 해법은 불투명을 디퍼드로 처리한 뒤, 반투명만 별도의 포워드 패스에서 뒤→앞 정렬로 그리는 하이브리드 구조입니다. 이때 반투명 패스는 디퍼드의 깊이 버퍼를 읽기 전용으로 사용해 불투명 뒤에 가려진 부분은 올바르게 클리핑되게 합니다.
68. 드로우콜이 많으면 왜 느려지나요?
병목이 GPU가 아니라 CPU 쪽 드라이버 오버헤드이기 때문입니다. 드로우콜마다 상태 변경 검증, 리소스 바인딩 해석, 커맨드 버퍼 기록, 유저 모드↔커널 모드 전환 등 고정 비용이 발생하고, D3D11에서는 이 작업이 대부분 단일 렌더 스레드에 몰립니다. 그래서 드로우콜이 수천~수만이 되면 GPU는 놀고 있는데 CPU 렌더 스레드가 프레임 시간을 다 소모하는 CPU 병목이 됩니다. 상태 변경(셰이더·텍스처 교체)이 잦을수록 콜당 비용도 커지므로, 해법은 컬링으로 콜 수 자체를 줄이고, 배칭·인스턴싱으로 콜을 합치고, 정렬로 상태 변경을 최소화하는 것입니다. 제 프로젝트에서 드로우콜 13,000 상황이 정확히 이 CPU 병목이었고, 메시 아일랜드 분할 + Hi-Z 컬링으로 89%를 줄여 해결했습니다.
69. 배칭이란 무엇인가요?
여러 오브젝트를 하나의 드로우콜로 묶어 그리는 기법입니다. 정적 배칭은 같은 머티리얼의 정적 오브젝트들의 정점을 월드 공간으로 미리 변환해 큰 버퍼 하나로 합쳐두는 방식으로, 런타임 비용이 없지만 메모리가 늘고 개별 컬링·이동이 어려워집니다. 동적 배칭은 매 프레임 작은 메시들을 CPU에서 합치는 방식으로, CPU 변환 비용과의 트레이드오프가 있습니다. 배칭의 전제는 머티리얼(파이프라인 상태)이 같아야 한다는 것이므로, 텍스처 아틀라스로 머티리얼을 통합하는 작업이 선행되는 경우가 많습니다. 같은 메시의 반복이라면 배칭보다 인스턴싱이 더 적합합니다.
70. 인스턴싱은 무엇인가요?
같은 메시를 다른 트랜스폼·파라미터로 여러 개 그릴 때, 드로우콜 하나(DrawIndexedInstanced)로 N개를 그리는 기법입니다. 메시 정점 데이터는 한 벌만 두고, 인스턴스별 데이터(월드 행렬, 색 등)를 별도 버퍼로 공급하면 GPU가 SV_InstanceID로 구분해 반복 처리합니다. 배칭과 달리 정점을 복제하지 않으므로 메모리 효율이 좋고, 수천 개의 풀·나무·잔해·군중 렌더링의 표준 해법입니다. 조건은 “동일 메시 + 동일 머티리얼”이며, 인스턴스별 차이는 인스턴스 버퍼로 표현 가능한 수준이어야 합니다.
71. 프러스텀 컬링은 어떻게 동작하나요?
카메라 절두체 밖의 오브젝트를 드로우콜 제출 전에 CPU에서 걸러내는 컬링입니다. 뷰-투영 행렬에서 절두체의 6개 평면을 추출하고, 각 오브젝트의 바운딩 볼륨(구 또는 AABB)을 6개 평면과 검사해 완전히 바깥이면 제외합니다. 구는 평면-중심 거리와 반지름 비교라 가장 싸고, AABB는 더 타이트한 대신 약간 비쌉니다. 오브젝트가 수만 개면 개별 검사도 부담이므로 쿼드트리/옥트리 같은 공간 분할로 노드 단위 선별 후 검사하는 계층 구조를 씁니다. 절두체 안에 있어도 다른 물체에 가려진 것까지는 거르지 못하며, 그것이 오클루전 컬링의 몫입니다.
72. 오클루전 컬링이란 무엇인가요?
절두체 안에 있지만 다른 물체에 가려져 보이지 않는 오브젝트를 걸러내는 컬링입니다. 방식으로는 미리 계산하는 포털/PVS, GPU 하드웨어 오클루전 쿼리(결과 회수 지연 문제), 그리고 런타임 깊이 기반 방식이 있습니다. 제가 구현한 것은 Hi-Z(Hierarchical-Z) 방식으로, 깊이 버퍼를 밉 체인으로 축소하되 각 단계에서 최댓값(가장 먼 깊이)을 취해 계층을 만들고, 오브젝트의 바운딩 볼륨을 화면에 투영해 그 영역을 덮는 밉 레벨의 깊이와 비교합니다. “이 영역에서 가장 먼 기존 깊이보다 내 가장 가까운 깊이가 더 멀다”면 확실히 가려진 것이므로 제외하는, 보수적이지만 안전한 판정입니다. 밉 계층 덕분에 큰 화면 영역도 소수의 샘플로 판정할 수 있다는 것이 핵심이며, 오픈월드형 맵의 드로우콜 89% 감소에서 메시 아일랜드 분할(컬링 단위를 잘게 쪼개 컬링 적중률을 높임)과 결합해 가장 큰 효과를 낸 부분입니다.
73. LOD는 무엇인가요?
Level of Detail로, 카메라와의 거리에 따라 오브젝트의 디테일 수준을 바꾸는 최적화입니다. 멀리 있는 오브젝트는 화면에서 몇 픽셀에 불과하므로 고폴리곤 메시가 낭비이며, 거리 구간별로 미리 만든 저폴리 버전(LOD0~N)으로 교체하고 최원거리에서는 빌보드(임포스터)나 컬링으로 대체합니다. 정점 처리 비용과 함께 픽셀이 작은 삼각형 문제(쿼드 오버셰이딩)도 완화됩니다. 핵심 이슈는 전환 순간의 팝핑으로, 전환 거리에 히스테리시스를 두거나 디더링/크로스페이드로 완화합니다. 메시 외에 텍스처(밉맵·스트리밍), 셰이더, 애니메이션 갱신 주기, AI 틱까지 거리 기반으로 낮추는 것을 모두 LOD 개념으로 묶을 수 있습니다.
74. CPU 병목과 GPU 병목을 어떻게 구분하나요?
측정으로 구분합니다. 기본 판별법은 ① CPU 프레임 시간과 GPU 프레임 시간(타임스탬프 쿼리)을 각각 재서 어느 쪽이 프레임을 결정하는지 보고, ② GPU 사용률이 낮은데 프레임이 안 나오면 CPU 병목(GPU가 명령을 기다리며 굶주림), GPU가 100%면 GPU 병목입니다. 간단한 실험으로는 해상도를 절반으로 낮춰보는 방법이 있습니다. 프레임이 크게 오르면 GPU(특히 픽셀) 병목, 변화가 없으면 CPU 병목입니다. CPU 병목이면 프로파일러로 게임 로직인지 렌더 제출(드로우콜)인지 다시 쪼개고, GPU 병목이면 76번의 방법으로 정점/픽셀 어느 쪽인지 좁힙니다. 제 드로우콜 최적화도 “해상도를 바꿔도 프레임이 그대로”라는 측정에서 CPU 렌더 제출 병목임을 특정하는 것에서 시작했습니다.
75. Fill Rate 병목이란 무엇인가요?
GPU가 픽셀을 채우는 처리량(초당 픽셀 수)이 한계에 달한 상태로, 픽셀 셰이딩과 렌더 타겟 쓰기(ROP)·메모리 대역폭 쪽의 병목입니다. 원인은 높은 해상도, 심한 오버드로우(특히 겹겹이 쌓인 반투명 파티클), 무거운 픽셀 셰이더, 많은 포스트 프로세싱 패스입니다. 판별은 해상도를 낮췄을 때 프레임이 비례해서 오르는지로 하며, 대응은 오버드로우 감소(정렬, 파티클 다이어트), 셰이더 경량화, 반투명·이펙트를 저해상도 버퍼에 렌더링 후 합성, 동적 해상도 스케일링입니다. 모바일 GPU에서 특히 자주 만나는 병목 유형입니다.
76. 버텍스 병목과 픽셀 병목은 어떻게 구분하나요?
변인 통제 실험으로 구분합니다. 렌더링 해상도만 낮췄을 때 프레임이 크게 개선되면 픽셀 쪽(픽셀 수에 비례하는 작업이 지배적), 거의 변화가 없다면 정점 쪽이나 다른 병목입니다. 반대로 지오메트리 부하만 바꾸는 실험, 즉 LOD를 강제로 낮추거나 폴리곤 수를 줄였을 때 개선되면 버텍스 병목입니다. GPU 프로파일러(PIX, Nsight, RenderDoc)를 쓰면 패스·드로우별 정점/픽셀 셰이더 시간과 하드웨어 카운터를 직접 볼 수 있어 더 정확합니다. 일반적으로 화면을 크게 덮는 씬은 픽셀 병목, 초고폴리곤·테셀레이션·먼 거리의 촘촘한 메시(픽셀보다 정점이 많은 상황)는 버텍스 병목 경향이 있습니다. 원칙은 “추측하지 말고 변인을 하나씩 바꿔 측정한다”입니다.
면접 활용 팁
- 최대 강점 구간: 65~68, 72, 74번은 부기님의 디퍼드 렌더링 + Hi-Z 컬링 + 드로우콜 최적화 경험과 직결됩니다. 이 질문들은 “일반론 → 제 엔진에서는 ~” 구조로 반드시 경험담까지 이어가세요. 89% 수치를 방어하는 자리이기도 합니다.
- 단골 콤보: 25→26→27→29번(비선형 깊이 → 정밀도 편중 → z-fighting → Reversed-Z), 37→38→39번(Early-Z → 오버드로우 → 반투명 예외), 65→66→67번(디퍼드 → G-Buffer → 반투명)은 세트로 나옵니다.
- 함정 주의: 10번(드로우콜의 진짜 비용은 CPU 드라이버 오버헤드)과 16번(클리핑을 나눗셈 전에 하는 이유)은 이해 깊이를 가르는 문제입니다.
- 측정 서사: 74~76번은 “추측 말고 측정” 원칙으로 답하고, 본인 최적화가 측정→병목 특정→구조적 해결 순서였음을 자연스럽게 연결하면 89% 주장의 신뢰도가 올라갑니다.