2. 발표자 소개
넥슨 9년차 프로그래머
현재 신규개발 3본부 1실 GTR팀 팀장
참여 프로젝트
마비노기
XBOX360 마비노기
마비노기2
주요 관심사
Computer Graphics
Real-Time Rendering
3. 발표 내용
개발 비용 대비 결과가 좋은 렌더링 기술을 10 가지 소개
지난 몇 년간의 마비노기2 개발 경험을 바탕으로 함.
반 나절 내로 적용할 수 있는 것도 있고 개발에 한두달 정도 필요한 것도 있음.
범용적이면서 독특한 기술 위주로 선정
마비노기2에 특화된 기술들은 제외.
너무 유명하거나 접하기 쉬운 기술도 제외.
주로 제가 개발한 것 위주로…
그래야 설명하기 쉽고 질문에도 답할 수 있습니다.
순위에 없다고 가성비 떨어지는 것은 아님!
4. 발표 순서
일반 기술 2개
렌더링 엔진 전체에 적용 가능한 기술 및 방법론.
프로젝트 관리 기술 3개
개발 과정을 기록으로 남기는 효과적인 방법.
팀 얼라인먼트를 도와주는 도구.
렌더링 기술 5개
렌더링 성능, 품질을 높여주는 기술.
6. 1. 시각적인 진단 도구
디버깅은 확률 게임
버그가 있는 위치를 추측해서 범위를 좁혀나가는 게임이다.
눈 감고 찍지 말고 사실에 근거해서 디버깅하자.
시각 정보는 가장 강력한 정보
소리보다 글자, 글자보다 그림, 그림보다 동영상이 이해하기 쉽다.
빠르고 정확한 진단을 위해 시각 정보를 최대한 활용하자
게다가 그래픽스 프로그래머는 팀에서 이것을 가장 잘 할 수 있는 사람이다.
7. 적용 사례 – 장비 커스터마이징
절단 대상 버텍스
절단면
아티스트가 정의한 장비 조합 절단면을 눈으로 관찰하고 문제점을 쉽게 찾을 수 있다.
10. 적용 사례 – 카메라 위치 정보
게임 카메라 위치.
디버그 카메라 시점에서
게임 카메라 상태를 진단.
11. 1. 시각적인 진단 도구 - 조언
무리해서라도 무조건 시각화
어떤 형태로든 반드시 보상받는다.
시각화 코드를 첫 번째 테스트 코드라고 생각하라
보통, 진단 코드는 대상 코드 전체를 사용하는 유일한 코드.
일종의 코드 커버리지 테스트를 수행하는 셈.
남에게 코드의 동작을 설명한다는 느낌으로 작성
실제로 이렇게 코드를 작성하다가 문제점을 조기에 발견하는 경우가 많다.
13. 2. LAA
의외로 이 옵션을 모르는 개발자가 많다
다들 알고 계실 듯 하지만 혹시 모르니 순위에 넣었음…
64bit가 가야 할 길이긴 하지만…
현실은 그렇게 만만하지 않았습니다.
자세한 정보는 아래 링크를 참고
2007 Gamefest, “Why Your Windows Game Won’t Run In 2,147,352,576 Bytes”
(http://download.microsoft.com/download/e/3/c/e3c25fea-2b53-4174-8729-
29a4ec16583b/Why%20Your%20Windows%20Game%20Won't%20Run%20In%202,147,352,576%20Bytes.zip)
14. 2. LAA
켜는 법
EXE 프로젝트의 속성창에서
‘큰 주소 처리’를 켠다.
DLL 프로젝트는 변경해도 의미 없다
(할 필요 없다).
15. 2. LAA - 추가 작업
이게 왜 ‘렌더링 테크닉’?
32bit 주소의 상위 1비트를 해킹하는 대표적인 코드가 D3DXEffect.
그래서 몇 가지 추가 작업이 필요하다
다음 슬라이드에서 설명…
16. 2. LAA - 추가 작업
모든 #include <d3dx9.h> 앞에
D3DXFX_LARGEADDRESS_HANDLE 매크로 정의
혹은 아래처럼 속성 시트에 정의
17. 2. LAA - 추가 작업
D3DXGetShaderConstantTable() 대신
D3DXGetShaderConstantTableEx()를 사용하고,
D3DXCONSTTABLE_LARGEADDRESSAWARE 추가
18. 2. LAA - 추가 작업
그리고,
이펙트 생성할 때 D3DFX_LARGEADDRESAWARE 옵션 추가.
이펙트 핸들 이름으로 스트링 사용 금지.
이게 전부
정말 쉽다.
20. 3. 클라이언트 동영상 인코딩
클라이언트에 동영상 인코딩 기능을 넣고 라이브 스트리밍
“팀장님, 이 작업 컨펌해주시고 오른쪽 아래 추천, 즐찾 부탁드려요~”
내부 클라이언트에서만 동작하는 ‘개발 전용 기능’
이 기능을 모두에게 공개하려면 넘어야 할 산이 많다.
일반 유저들은 아*** 같은 서비스를 사용하는 것이 효율적이다.
동영상은 생각을 공유하는 강력한 도구
그리고 개발 과정을 효과적으로 기록에 남길 수 있다.
25. 3. 클라이언트 동영상 인코딩 – 우리는 이렇게 활용한다
아침 정기 게임 플레이
테스트 그룹 내에서 돌아가면서 녹화한다.
게임 플레이 장면을 팀 전체가 볼 수 있다.
디렉터 지시
디렉터의 모범 플레이를 학습한다.
기획 의도를 설명하는데 효과적이다.
디버깅 자료
“그 버그 재현법은 몇 월 며칠 영상 어디어디를 보세요”
26. 3. 클라이언트 동영상 인코딩 - 구현
클라이언트 Flash
Media Sever 인코딩 서버가 전송한
H.264로 인코딩 스트림을 포워딩
(nVidia CUDA Video Encoder)
FLV로 변환후 FMS
RTMP로 전송
인코딩 서버 서버 스크립트
동영상 스트리밍
임의로 하나 선택
플래시 플레이어 플래시 플레이어
동영상 폴더 P2P로 채팅
플래시 플레이어 플래시 플레이어
27. 3. 클라이언트 동영상 인코딩 – H.264 인코딩
H.264 비디오 인코딩은 GPU로 처리
nVidia CUDA Video Encoder를 사용한다.
(http://developer.download.nvidia.com/compute/DevZone/docs/html/C/doc/CUDA_VideoEncoder_Library.pdf)
CUDA를 지원하지 않거나 nVidia GPU가 아니면 motion jpeg 포맷으로 CPU 인코딩한다.
(ATI 님들 제발 GPU 인코딩 API좀 공개해주세요…)
오디오는 WASAPIWindows Audio Session API 사용
http://msdn.microsoft.com/en-us/library/windows/desktop/dd371455(v=vs.85).aspx
인코딩한 데이터는 25fps로 인코딩 서버에 전달된다
bitrate와 fps는 조절 가능.
28. 3. 클라이언트 동영상 인코딩 – 인코딩 서버
인코딩 서버는 클라이언트가 보낸 패킷을 동영상으로 변환
클라이언트가 전송한 비디오와 오디오 패킷을 합쳐서 동영상으로 만든다.
서버는 C#으로 제작, 동영상 생성은 ffmpeg(www.ffmpeg.org)를 사용.
클라이언트가 없을 동안에는 동영상 폴더에서 임의로 하나 재생.
동영상은 ffmpeg를 사용해서 FMS로 전달
FMS : Flash Media Server.
RTMP(Real Time Messaging Protocol)을 사용해서 전달한다.
동영상을 파일로도 저장한다.
이것 역시 ffmpeg를 사용해서 처리한다.
29. 3. 클라이언트 동영상 인코딩 - FMS
FMS로 팀 전체에 동영상을 라이브 스트리밍
FMS로 인코딩 서버가 전송한 동영상을 팀 전체 네트워크에 배포한다.
샘플에 들어있는 multicast 서버 스크립트를 약간 고쳐서 사용 중.
Flash Media Interactive Server 4.5를 사용
가격은 500만원 정도(US $4,500).
평가판(Flash Media Development Sever)를 사용해도 무방하나,
동접 제한(10명)이 있고 일정 길이(30분)가 넘는 동영상은 스트리밍이 중지된다.
아래 두 링크를 참고:
http://www.adobe.com/products/flash-media-interactive.html
http://www.adobe.com/products/flash-media-server-family/buying-guide-comparison.html
30. 3. 클라이언트 동영상 인코딩 – 플래시 플레이어
FMS가 배포하는 스트림을 플래시 플레이어로 재생
FMS에 들어있는 샘플 플레이어를 바탕으로 대충 만들었다.
플래시라서 웹 페이지에서 사용하기 쉽다.
채팅은 플래시의 P2P 기능을 사용
플래시 최근 버전에 들어있는 P2P 기능을 사용해서 채팅을 구현.
31. 4. 스크린샷 히스토리
스크린샷을 생성하면 공유 폴더에 사본 복사
정말 간단한 기능이지만 아주 유용하다.
우리의 경우, 한달 평균 850 장 정도가 저장된다.
32. 4. 스크린샷 히스토리
활용
작업 정기 리뷰, 리포트 작성시 짤방으로 자주 사용된다.
변경점 추적이나 디버깅 할 때도 유용하다.
남는 건 사진 뿐
심심할 때 예전 스크린샷을 보면 추억 돋는다.
33. 5. 프로파일링 DB
클라이언트의 주요 지표를 DB에 저장
DB에 저장해 두면 가공해서 여러 용도로 활용하기 쉽다.
하드웨어 구성 별 클라이언트 성능 정보를 수집
특정 하드웨어에서 발생하는 성능 이슈를 추적할 수 있다.
어셋 지표는 수동으로 DB에 기록
주기적으로 담당자가 수집 프로그램을 실행.
클라이언트 성능 지표는 실행 중에 자동으로 전송
매 1분마다 DB에 전송한다.
35. 적용 사례 – 클라이언트 성능 프로파일링
다른 팀원들의
데이터 조회
프로젝트 포탈
사이트에 간략하게
표시
36. 5. 프로파일링 DB – 구현
클라이언트는 웹페이지를 통해 자료를 전송
C++로 DB에 직접 접속하려면 여러 가지로 번거롭다.
HTTP Request 등으로 간단하게 처리 가능
예) http://perfdb.deskcast.com/GameClient/default.aspx?id=henjeon&fps=60
자료 수집보다 분석하고 시각화하는 프로세스가 중요
주기적으로 자료를 분석하고 유의미한 정보를 찾으려 노력해야 한다.
“시각적인 진단 도구” 가 역시 중요하다.
38. 6. 텍스쳐 스트리밍
저해상도 텍스쳐(썸네일)를 먼저 보여주고,
텍스쳐 요청이 들어오면 저해상도 텍스쳐를 로딩.
크기가 작기 때문에 빠르게 로딩 가능.
천천히 고해상도 텍스쳐를 로딩한 후,
백그라운드 작업 스레드에서 처리한다.
고해상도 텍스쳐로 교체
썸네일을 새 텍스쳐로 교체한다.
39. 6. 텍스쳐 스트리밍
장점
로딩 응답 시간을 줄일 수 있다.
모든 썸네일을 미리 로딩해두면 요청 즉시 렌더링에 사용할 수 있다.
무조건 텍스쳐의 모든 밉맵을 로딩하지 않고, 필요한 밉맵만 로딩한다면
비디오 메모리를 절약할 수 있다.
단점
“만들기 정말 귀찮다”
40. 6. 텍스쳐 스트리밍 - 구현
필요한 밉맵 레벨 계산
메시에 매핑된 텍스쳐의 텍셀:픽셀 비율이 1 이상이 되는 밉맵 레벨을 찾는다.
계산에 필요한 값
화면 해상도
메시의 중심 위치
그리고 텍스쳐 스케일
41. 6. 텍스쳐 스트리밍 - 구현
텍스쳐 스케일 pos: (2, 5)
uv: (0.5, 0)
메시의 uv 길이와 월드 길이의 비율.
텍스쳐를 확대해서 매핑할 수록 이 값은 작다.
ts: 0.19
ts: 0.09
메시 전처리 단계에서 미리 계산
우리의 경우, 모든 엣지의 텍스쳐 스케일을
계산한 후에 그 평균값을 사용한다.
pos: (5, 1)
uv: (1, 0.8)
ts: 0.25
pos: (0, 0)
uv: (0, 0)
메시 ts = (0.09 + 0.19 + 0.25) /3 = 0.18
42. 6. 텍스쳐 스트리밍 - 구현
이제 계산해보자
메시의 크기가 변경되지 않는다고 가정(스케일 애니메이션이 없다고 가정)
43. 6. 텍스쳐 스트리밍 - 구현
텍스쳐 교체는 두 가지 상황에서 발생한다
카메라가 메시로 다가올 때 : 고해상도 텍스쳐로 교체
카메라가 메시에서 멀어질 때 : 저해상도 텍스쳐로 교체
저해상도 텍스쳐로 교체하기는 쉽다
그냥 바로 바꿔도 사람이 알아채기 어렵다.
고해상도 텍스쳐로 교체하면 눈에 잘 띈다
이른바 ‘텍스쳐 팝핑popping’ 현상.
44. 6. 텍스쳐 스트리밍 - 구현
저해상도 텍스쳐를 고해상도 텍스쳐로 부드럽게 전환
이미지를 조금씩 변경시키면 팝핑 현상을 줄일 수 있다.
정답은 없다
트랜지션은 공짜가 아니다: 크지는 않지만 실행 부하가 있다.
트랜지션 없이 바로 바꾸는 것을 선호하는 사람도 많다.
45. 6. 텍스쳐 스트리밍 - 구현
밉맵 LOD 바이어스로 소프트 트랜지션 처리
SetSamplerState(…, D3DSAMP_MIPMAPLODBIAS, …)
교체할 두 텍스쳐의
밉맵 개수 차이. 이 값을 조금씩
줄이고, 0이 되면 트랜지션 종료
46. 6. 텍스쳐 스트리밍 – 소프트 트랜지션
로딩 완료 새 텍스쳐로 교체 트랜지션 중 트랜지션 완료
MipMap LOD Bias = n MipMap LOD Bias = k, 0<k<n MipMap LOD Bias = 0
47. 7. TEXCOORDN
셰이더 소스 코드 생성시 전처리되는 커스텀 키워드
비슷한 키워드로 COLORN이 있다.
사실, C***** 셰이더를 보고 도입(=따라함).
전처리문을 많이 사용하는 셰이더 코드 작성시 아주 유용
구조체 정의할 때 #if를 많이 쓰고 있다면 이 기능이 반드시 필요.
53. 8. 업스케일링
저해상도로 3D 장면을 렌더링하고 그 결과를 확대해 사용
비싼 픽셀 셰이더 계산 시간을 줄이는 테크닉.
콘솔 게임에서 많이 사용한다.
UI와 2D 요소는 1:1로 렌더링한다.
인터페이스가 뭉개지거나 폰트가 번지는 것은 참을 수 없다.
54. 8. 업스케일링 - 구현
그냥 Bilinear Filtering로 업스케일링
이것 저것 다 해봤는데 결과가 좋지 않았다.
복잡한 업스케일링 셰이더를 쓰면 오히려 더 느려지는 경우도 있다.
팁: 세로 해상도를 더 확보하는 것이 인지적 측면에서 유리.
프레임버퍼 해상도에 비례해서 렌더 타겟을 생성
아래와 같이 렌더 타겟을 생성하는 기능이 있다면 업스케일링 구현은 공짜.
56. 9. 버텍스 단위 3축 조명
Per Vertex Radiosity Normal Mapping
소스엔진 Radiosity Normal Mapping의 버텍스 단위 버전.
너무나 유명한 기법이므로 자세한 설명은 생략.
(http://www2.ati.com/developer/gdc/D3DTutorial10_Half-Life2_Shading.pdf)
개발 동기
A. 우리는 배경의 렌더링 품질을 위해서 래디어시티 노멀 맵을 써야 한다.
B. 그냥 텍스쳐로 구워버리면 너무 용량이 크므로 압축해야 함.
C. 번지 처럼 박사 학위급 논문 쓰면서 빡시게 압축할 수 있겠니?
D. 에라 모르겠다 버텍스에 넣고 잊자.
65. 9. 버텍스 단위 3축 조명 - 구현
3DSMAX 에서 조명 계산
자체 제작한 플러그인에서 계산하고 출력(export)한다.
최근 작업으로 GPU(CUDA)로 계산하는 기능이 추가되어 성능이 크게 개선되었다.
쓸만한 버텍스 단위의 GIGlobal Illumination 솔루션이 없다
거의 대부분의 솔루션들은 픽셀 단위 처리만 지원.
조명 계산 대부분을 직접 제작할 각오를 해야 함(TA 만세!!).
66. 9. 버텍스 단위 3축 조명 - 구현
탄젠트 공간Tangent Space 대신 라이트 공간Light Space 베이시스Basis 사용
라이트 좌표계는 버텍스의 노멀을 Z축으로 하는 좌표계로,
탄젠트 좌표계와 비슷하지만 UV맵과 무관한 좌표계이다.
노멀 벡터가 같은 버텍스는 라이트 베이시스도 같다.
특징
+ 저작할 때 인접 면의 UV를 90도 이상 돌려서 매핑해도 괜찮다(저작 편의성).
+ UV매핑을 수정해도 이미 계산한 조명을 재사용할 수 있다(빠른 이터레이션).
- 약간의 런타임 셰이더 비용이 증가한다(런타임 성능 저하).
67. 10. 컨택트 섀도(Contact Shadow)
CS는 매우 중요하다
CS는 캐릭터와 지면을 밀착시켜 주고,
떠 있다는 느낌을 없앤다.
물론 Creep Score도 중요하다…
그림자와 SSAO만으로는 부족
그림자에는 강도가 없고,
SSAO는 CS용으로 튜닝하기 어렵다.