2026 게임 프로그래밍 셰이더 디버깅 숨은 팁 9가지

profile_image
작성자 셰이더탐정 시온
댓글 0건 조회 3회

캐릭터가 검게 변하고, 특정 그래픽카드에서만 화면이 깜빡이며, 에디터에서는 정상인데 빌드에서 셰이더가 깨진다면 어디부터 확인하시나요? 셰이더 문제는 코드 한 줄보다 렌더링 상태, 좌표계, 정밀도, 리소스 바인딩이 복합적으로 얽힌 경우가 많습니다. 무작정 수식을 고치기 전에 관찰 가능한 값으로 바꾸는 습관만 들여도 디버깅 시간이 크게 줄어듭니다.

이 글은 Unity, Unreal Engine, 자체 엔진에 공통으로 적용할 수 있는 게임 프로그래밍 셰이더 디버깅 요령을 다룹니다. 2026년의 GPU 기반 개발 환경에서도 유효하도록 캡처 도구에만 의존하지 않고, 코드와 화면 자체를 진단 장치로 활용하는 숨은 팁을 중심으로 구성했습니다.

색상을 로그처럼 사용해 중간값을 눈으로 읽기

벡터와 스칼라를 디버그 색상으로 치환합니다

GPU 셰이더에는 CPU 코드처럼 편리한 로그 출력이 없거나, 출력 기능을 켜는 순간 실행 조건이 달라질 수 있습니다. 이럴 때 가장 빠른 방법은 최종 색상을 잠시 버리고 확인하려는 값을 RGB에 직접 넣는 것입니다. 예를 들어 월드 노멀은 normal * 0.5 + 0.5로 변환하면 음수 범위를 화면에 표시할 수 있고, 거칠기나 깊이 같은 스칼라는 세 채널에 같은 값을 넣어 회색조로 관찰할 수 있습니다.

다만 값 하나를 화면에 띄우는 것만으로는 범위를 놓치기 쉽습니다. 예상 범위가 0~10이라면 먼저 10으로 나누고, 범위를 벗어난 픽셀에는 빨강이나 자홍색을 칠해 별도의 경고로 표시하세요. 정상값을 예쁘게 보는 것보다 비정상값이 어디서 시작되는지 찾는 것이 핵심입니다. 카메라를 움직일 때 색이 함께 변한다면 월드 공간으로 기대했던 데이터가 뷰 공간일 가능성도 의심할 수 있습니다.

더 잘 알려지지 않은 방법은 비트 플래그를 색상 채널에 나누는 것입니다. 재질 분기, 그림자 수신 여부, 스킨 메시 여부를 각각 R, G, B에 할당하면 어떤 변형 경로가 선택됐는지 한 장면에서 확인할 수 있습니다. 복잡한 포트폴리오 프로젝트를 점검할 때도 이 방식은 설명 가능한 디버그 뷰를 만드는 데 유용합니다.

  • 노멀: 음수 범위를 0~1로 재매핑하고 길이가 1인지 별도 색으로 검사합니다.
  • UV: frac 함수를 적용해 반복 주기와 뒤집힘을 확인합니다.
  • 깊이: 선형화 전후 값을 번갈아 표시해 원근 투영 오류를 찾습니다.
  • NaN 경고: 비정상 수치가 감지된 픽셀을 강한 자홍색으로 고정합니다.
디버그 색상은 임시 효과가 아니라 GPU용 계측기입니다. 자주 쓰는 뷰를 공통 헤더나 엔진의 디버그 패스로 만들어 두면 다음 프로젝트에서도 그대로 활용할 수 있습니다.

NaN과 무한대가 퍼지기 전에 발생 지점을 봉쇄하기

최종 화면이 아니라 위험한 연산 직후를 검사합니다

화면 일부가 번쩍이거나 블룸이 갑자기 폭발한다면 텍스처보다 먼저 NaN과 무한대를 의심해 보세요. 0으로 나누기, 음수에 대한 제곱근, 범위를 벗어난 역삼각함수, 길이가 0인 벡터의 정규화가 대표 원인입니다. 한 픽셀에서 생긴 비정상 값은 후처리의 다운샘플과 블러를 거치면서 넓은 영역으로 번져 원인을 감춥니다.

숨은 요령은 최종 출력 직전에 한 번 검사하는 대신 위험 연산 바로 다음 줄마다 단계적으로 경고색을 다르게 지정하는 것입니다. 정규화 뒤에는 빨강, 조명 합산 뒤에는 초록, 톤 매핑 전에는 파랑을 출력하도록 하면 최초 발생 구간을 빠르게 좁힐 수 있습니다. HLSL의 isfinite 계열 기능이나 GLSL의 isnan, isinf 지원 여부는 셰이더 모델과 플랫폼에 따라 확인하고, 지원이 제한되면 값이 자기 자신과 다른지 비교하는 NaN 검사 같은 대안을 사용할 수 있습니다.

무조건 saturate로 덮는 방식은 권하지 않습니다. 화면은 정상처럼 보일 수 있지만 잘못된 수학이 숨겨져 다른 기기에서 다시 터질 수 있기 때문입니다. 출시 빌드에서는 안전한 기본값으로 복구하되, 개발 빌드에서는 픽셀 좌표나 패스별로 눈에 띄는 진단 색상을 남기는 이중 정책이 실용적입니다. 수학 라이브러리에도 safeNormalize, safeRcp처럼 의도가 드러나는 함수를 두면 셰이더 코드 리뷰가 쉬워집니다.

  1. 분모에 작은 epsilon을 더하기 전에 왜 0이 됐는지 먼저 확인합니다.
  2. dot 결과를 acos에 넣기 전 -1~1 범위로 제한합니다.
  3. 정규화 대상의 길이 제곱을 검사하고 0이면 합리적인 기본 방향을 사용합니다.
  4. HDR 색상은 톤 매핑 전에 최대 휘도와 유한 여부를 따로 표시합니다.
  5. 진단 매크로를 개발 빌드에서만 활성화해 출시 성능을 보호합니다.

좌표계 오류를 축 색상과 패턴으로 추적하기

공간 변환 순서를 한 단계씩 끊어 봅니다

셰이더 버그 가운데 오래 걸리는 유형은 오브젝트, 월드, 뷰, 탄젠트 공간을 섞어 쓰는 문제입니다. 이름이 normal이나 lightDir처럼 모호하면 코드만 읽어서 공간을 판별하기 어렵습니다. 변수명에 WS, VS, TS 같은 접미사를 붙이고, 행렬을 적용할 때 위치에는 동차 좌표 1, 방향에는 0을 쓰는 원칙을 명시하면 실수가 크게 줄어듭니다.

비균일 스케일이 있는 오브젝트에서는 방향 벡터와 노멀의 변환 방식이 같지 않습니다. 모델 행렬을 노멀에 그대로 곱하면 조명이 기울어질 수 있으므로 역전치 행렬이나 엔진이 제공하는 노멀 변환 함수를 사용해야 합니다. 겉으로는 특정 각도에서만 하이라이트가 흔들려 아트 리소스 문제처럼 보이지만, 단위 구나 비균일하게 늘린 큐브를 테스트 장면에 배치하면 차이를 즉시 확인할 수 있습니다.

또 하나의 꿀팁은 체크무늬 텍스처 대신 축마다 색과 주기가 다른 절차적 격자를 사용하는 것입니다. X축은 빨강, Y축은 초록, Z축은 파랑으로 만들고 양의 방향에는 밝은 띠를 추가하면 반전과 축 교환까지 알아낼 수 있습니다. 팀 내 역할과 제작 흐름을 설명할 때 참고할 수 있는 게임 기획자 용어 자료처럼, 좌표계 규칙도 문서에 남겨 기획 데이터와 프로그래밍 구현이 서로 다른 기준을 쓰지 않게 해야 합니다.

  • 행렬 곱 순서와 벡터의 행·열 규약을 엔진 전체에서 하나로 고정합니다.
  • UV 원점이 좌상단인지 좌하단인지 렌더링 API별로 기록합니다.
  • 탄젠트의 w 부호와 미러 UV 처리 경로를 확인합니다.
  • 카메라 이동 시 패턴이 표면에 붙어 있는지 관찰해 공간을 판별합니다.
  • 테스트 모델에는 회전, 음수 스케일, 비균일 스케일을 모두 적용합니다.

셰이더 변형과 리소스 바인딩 누락을 잡는 방법

정상 재질과 고장 재질의 차이를 최소 단위로 줄입니다

에디터에서는 보이지만 실제 빌드에서 분홍색 재질이나 검은 오브젝트가 나타난다면 셰이더 변형 제거, 키워드 조합, 상수 버퍼 정렬, 텍스처 바인딩을 살펴봐야 합니다. 특히 기능 토글을 키워드로 계속 추가하면 변형 수가 기하급수적으로 늘어나고, 빌드 시스템이 사용하지 않는다고 판단한 조합을 제거할 수 있습니다. 문제가 난 재질의 키워드 목록을 정상 재질과 비교하면 코드 전체를 읽는 것보다 빠릅니다.

리소스 이름이 맞는데도 값이 이상하다면 CPU 구조체와 GPU 상수 버퍼의 패딩 차이를 확인하세요. float3 다음에 float 하나가 있다고 해서 모든 언어와 API에서 항상 기대한 배치가 보장되는 것은 아닙니다. 오프셋을 명시적으로 출력하거나 리플렉션 정보와 대조하고, 디버그 단계에서는 float4 단위로 묶어 모호성을 줄이는 편이 안전합니다. 텍스처가 없을 때는 검정 기본값보다 용도별 진단 텍스처를 연결하면 누락 사실을 즉시 알 수 있습니다.

변형 문제를 재현할 때는 화려한 본 장면을 그대로 붙들지 마세요. 메시 하나, 재질 하나, 광원 하나로 구성한 최소 장면을 만들고 동일한 빌드 파이프라인을 통과시키는 편이 효율적입니다. 국제 게임 개발 사례와 기술 발표를 찾는 출발점으로는 GDC 관련 지식백과 설명도 참고할 수 있습니다. 발표 기법을 그대로 복사하기보다 자신의 엔진에서 재현 가능한 체크 항목으로 바꾸는 것이 중요합니다.

  1. 고장 난 픽셀을 만드는 패스와 셰이더 변형 이름을 먼저 기록합니다.
  2. 키워드를 절반씩 비활성화하는 이분 탐색으로 문제 조합을 좁힙니다.
  3. 모든 선택 텍스처에 빨강, 초록, 파랑 등 서로 다른 기본 리소스를 지정합니다.
  4. CPU와 GPU 양쪽에서 상수 버퍼의 크기와 멤버 오프셋을 비교합니다.
  5. 개발 빌드가 실제 사용한 변형 목록을 보존하도록 빌드 로그를 설정합니다.

GPU 캡처를 열기 전에 프레임을 재현 가능하게 만들기

한 프레임의 입력과 상태를 고정합니다

RenderDoc, PIX, Nsight Graphics 같은 캡처 도구는 강력하지만, 문제가 매번 다른 프레임에 나타나면 캡처 파일도 매번 달라집니다. 먼저 카메라 위치, 애니메이션 시간, 난수 시드, 해상도, 동적 해상도 비율을 고정하세요. 시간 기반 노이즈나 바람 효과는 별도의 디버그 시간 값을 받도록 만들면 같은 프레임을 반복 비교할 수 있습니다.

캡처에서는 결과 텍스처만 보지 말고 문제 드로 호출의 입력부터 역방향으로 따라가야 합니다. 인덱스 버퍼와 정점 속성이 정상인지, 렌더 타깃 포맷과 뷰포트가 맞는지, 깊이·블렌드·컬 상태가 예상과 같은지 확인한 뒤 셰이더 입력과 중간 리소스를 살펴보세요. 코드가 맞아도 이전 패스의 리소스 상태 전환이나 잘못된 배리어 때문에 오래된 데이터를 읽을 수 있습니다.

팀 예산이 제한되어 있다면 모든 개발자에게 최고 사양 GPU를 제공하기보다 대표 제조사와 성능 등급을 나눈 테스트 기기 구성이 낫습니다. 장비와 디버깅 시간의 우선순위를 세울 때는 계획예산 제도의 개념처럼 목표와 비용을 연결해 생각할 수 있습니다. 무료 캡처 도구, 자동 스크린샷 비교, 실제 기기 테스트를 조합하면 작은 개인 프로젝트에서도 꽤 촘촘한 검증망을 만들 수 있습니다.

  • 재현 정보: 장면, 좌표, 카메라, 프레임 번호, 난수 시드를 함께 저장합니다.
  • 상태 검사: 셰이더 코드 전에 뎁스, 블렌드, 컬링, 뷰포트를 확인합니다.
  • 리소스 검사: 해당 프레임에 실제 연결된 텍스처와 버퍼를 확인합니다.
  • 비교 캡처: 정상 GPU와 문제 GPU에서 같은 입력으로 한 프레임씩 확보합니다.
  • 최소 장면: 문제가 유지되는 범위에서 오브젝트와 패스를 계속 제거합니다.

이것만은 꼭 기억할 셰이더 디버깅 체크리스트

고치기 전에 증거를 남겨 재발을 막습니다

버그가 사라졌다고 바로 진단 코드를 삭제하면 같은 문제가 다시 나타났을 때 처음부터 조사해야 합니다. 디버그 뷰, 최소 재현 장면, 정상 캡처 이미지, 발생 조건을 프로젝트 자산으로 남겨 두세요. 특히 아트 에셋이나 엔진 버전이 바뀔 때 실행하는 화면 회귀 테스트에 해당 장면을 추가하면 육안으로 찾기 어려운 노멀 반전과 색 공간 오류도 조기에 잡을 수 있습니다.

수정 전후에는 성능도 함께 비교해야 합니다. 안전 검사와 분기문을 추가해 화면은 고쳤지만 웨이브 발산이나 레지스터 사용량이 증가할 수 있기 때문입니다. 개발용 진단 로직은 컴파일 플래그로 분리하고, 출시 경로에는 검증된 최소 보호 코드만 남기세요. 반대로 모바일처럼 정밀도 문제가 잦은 플랫폼에서는 성능을 이유로 모든 변수를 낮은 정밀도로 내리지 말고, 누적 좌표와 깊이 계산처럼 민감한 구간에 높은 정밀도를 선택적으로 유지하는 편이 좋습니다.

마지막으로 스스로 세 가지를 물어보세요. 이 값은 어느 좌표계에 있는가, 유효 범위는 어디까지인가, 어느 패스가 처음 만들었는가? 이 질문에 답할 수 없다면 아직 셰이더를 고칠 단계가 아니라 관찰 장치를 추가할 단계입니다. 색상 로그 → 비정상 수치 차단 → 좌표계 검증 → 변형 비교 → 고정 프레임 캡처 순서로 접근하면 복잡한 게임 프로그래밍 프로젝트에서도 원인을 훨씬 체계적으로 좁힐 수 있습니다.

  • 문제 장면과 카메라를 저장하고 재현 성공률을 기록했는가?
  • 중간값의 범위, 단위, 좌표계를 색상으로 확인했는가?
  • NaN과 무한대가 최초로 발생한 연산을 찾았는가?
  • 정상·비정상 셰이더 변형과 렌더링 상태를 비교했는가?
  • 수정 사항을 자동 화면 테스트와 개발 문서에 반영했는가?
좋은 셰이더 디버깅은 감으로 수식을 바꾸는 작업이 아닙니다. 보이지 않는 GPU 상태를 작은 증거로 바꾸고, 그 증거를 한 단계씩 비교하는 게임 개발 과정입니다.

2026 게임 프로그래밍 셰이더 디버깅 숨은 팁 9가지

댓글목록

등록된 댓글이 없습니다.