2011년 11월 24일 목요일

디퍼트 라이팅 엔진에서 Oren-Nayar 조명 쓰기


그래픽스 프로그래밍 관련 블로그를 가끔 보는 편이다. 일단 이게 새로운 기법을 배우는데 도움이 되니까... 그런데 가끔씩 실제 경험보다는 그냥 이론에 치우쳐 사실이 아닌걸 우기는 블로그 포스트들이 있어서 좀 맘이 불편하다.

일례로 다음은 다른 그래픽 프로그래머와 나눈 대화 중 하나:
  • 다른놈: "우리 엔진은 디퍼트 라이팅이라 오렌 네이어(Oren-Nayar) 조명을 쓰는건 매우 힘들어"
  • 나: "먼 개소리? -_- 졸 쉬워~"
  • 다른놈: "아냐아냐 그렇지 않아. 이 블로그에서 힘들다고 했어."
  • 나: "으음... -_- 근데 난 이미 2년전에 울 엔진에서 구현했는걸? 매우 쉬워."
  • 다른놈: "허걱~~" ( 땀을 삐질.. -_-;;;; )
그래서 그놈에게 어떻게 해는지를 설명해 줬다...... 그리고 이놈처럼 잘못된 글 때문에 혼돈스러워 하시는 분들을 위해 여기에도 설명을....

우선 사전 지식.....

Oren-Nayar가 뭔지 모르시는 분들은 여기를 우선 보시길... 텍스처 룩업을 통해 최적화하는 방법도 소개함... 그 외에 울 팀에서 자체적으로 만든 approximation 함수도 있음... 내 맘대로 Oren-Nayar 조명을 간단히 설명하자면, 거칠음(roughness)을 조명 계산공식에 반영하는 diffuse 조명 모델이라고 하겠음....

그리고... 디퍼드 라이팅이 뭔지 모르시는 분들은 여기를 볼 것.

이 정도면 사전지식도 된듯 하니 본격적으로 설명을 하면..... Oren-Nayar조명을 하려면 기타 조명에 비해 다른 정보 하나가 필요하다. 거칠은 정도. 그럼 디퍼드 라이팅 엔진에서 Oren-Nayar를 하려면 어떻게 할까? 거칠은 정도를 G 버퍼에 저장하면 끝.... 물론 G 버퍼에 거칠은 정도를 저장하는 법은 여러가지가 있는데... 이게 사람들이 많이 혼돈스러워 하는 부분일 듯 하다.

대부분의 디퍼드 라이팅 엔진은 법선(normal)의 XY를 G 버퍼의 R16G16에 저장하는 듯 하다. 그러면 이 별도의 정보(거칠은 정도)를 저장하려면 렌더타겟이 하나 더 필요하단 이야기지... 렌더타겟을 하나 더 사용하면 메모리도 더 먹고 속도도 느려지므로 그닥 좋은 방법은 아님.

다른 방법은 법선을 8비트 채널에 저장하는 방법... 이것의 단점은 8비트 자체의 정밀도(precision)가 떨어져서 조명 결과가 부드럽지 않게 나오는 것.... 하지만 Crytek에서 발표한 best-fit normal을 사용하면 R8G8B8 채널에 법선을 제대로 저장할 수 있다. (스페이스마린에서도 한동안 이 방법을 사용했었음.). 일단 이렇게 법선을 저장하고 나면 마지막 alpha채널에 거칠은 정도를 저장할 수 있으니.... 문제해결........ 일까?

그러니 내가 구현한 방법은 이보다는 조금 더 복잡했다. 스페큘라 파워(specular power)도 저장해야 했거든... 곰곰히 생각해보니 스펙 파워에 굳이 8비트를 전부다 사용할 일이 없더라... (정말 127이상의 스펙 파워를 쓰는 경우가 얼마나 있을까? 11 미만의 스펙 파워를 쓰는 경우도 거의 없을듯?) 그래서 스페큘러 파워에 7비트만을 사용하고 거칠은 표면인지를 나타내는 플래그에 1비트를 사용하기로 했다.

on/off로 거칠은 정도만 표현하면 되냐고? 물론 아니다. 조금더 생각해보면 거칠은 정도란 결국 스페큘러 파워의 역함수임을 알 수 있었다. 거칠은 표면은 조명을 더욱 고르게 산란시키므로 스페큘러 파워가 적어야 하고, 매끄러운 표면은 그 반대이므로 스페큘러 파워가 높아야 하고....

이런 관찰 결과를 내 맘대로 대충 함수로 짜보니 이런 꼴이 되더라...

G-버퍼 저장법
  • RGB: 법선
  • A: 거칠음/스펙 파워의 짬뽕
매우 간략화시킨 디퍼드 라이팅 쉐이더 코드

float4 gval = tex2D(Gbuffer, uv);

// Crytek의 기법을 사용하여 법선을 decode
float3 normal = decodeNormal(gval.xyz);  


float specpower = gval.a;
float roughness = 0;
if (specpower > 127)
{
    specpower -= 127;
    roughness = someHackeryCurveFunction(127 - specpower);
}

// 이제 이 변수를 이용하여 올바른 조명을 계산할 것...


이정도면 별로 안어렵지? Xbox 360과 PS3에서도 별로 느리지 않은 방법이었다. 물론 approximation을 이용해 Oren-Nayar를 최적화시키기도 했지만.....

2011년 11월 20일 일요일

[포프의 쉐이더 입문강좌] 00. 들어가며


(원래 출판을 목적으로 썼던 책인데 출판사 사정으로 책 출판이 어려워져 인터넷에 그대로 공개합니다.)

들어가며

안녕하세요. 캐나다 렐릭 엔터테인먼트에서 시니어 그래픽 프로그래머로 일하고 있는 포프입니다. 이 쉐이더 입문 책은 제가 2007년 1월부터 2009년 12월까지 3년간 캐나다의 The Art Institute of Vancouver 대학에서 쉐이더 프로그래밍 강의를 하면서 축적한 자료와 지식을 글로 옮겨 놓은 것입니다.

책을 쓰게 된 배경
2007년에 제가 강의를 시작할 때, 수업시간에 사용할 교과서를 찾으려고 참 많은 노력을 했습니다. 하지만 시중에 나와있는 책들 중, 쉐이더 입문과목에 적합한 놈이 없더군요. (몇 년이 지난 지금에도 마찬가지인 것 같습니다.) 시중에 나와있는 쉐이더 책들은 대부분 이미 쉐이더 코드를 짤 줄 아는 중고급 프로그래머를 위한 것이었습니다. 따라서 쉐이더에 입문하는 학생들이 보면 뭔 소린지 몰라서 그냥 포기할 게 뻔했죠. 그나마 쉐이더 입문 내용이 DirectX 책에 담겨있는 경우가 있었지만 그 중에서도 마땅한 책이 없다고 생각했던 이유가
  • 쉐이더는 구색 맞추기 식으로 넣어놓아서 너무 수박 겉 핥기 식이다.
  • 학계에 계신 분들이 쓴 책은 너무 이론이나 문법에만 치우쳐져 있다.
  • 실무에 그다지 쓸모가 없는 내용들을 너무 많이 담고 있다.
  • 지면수만 많아 책값이 너무 비싸다.


등 이었습니다. 그래서 결국엔 교과서 없이 강의를 시작했죠. 이론이나 수학에 치우치기 보다는 실무에 곧바로 쓸 수 있거나 실무에서 쓸 수 있는 기법의 기초가 되는 내용들만을 가르치는데 주력했습니다. 강의를 하면서 좋았던 점은 저는 그리 어렵지 않다고 생각해왔는데 학생들이 이해하지 못하는 부분들을 알아낼 수 있다는 거였죠. 그래서 그걸 다시 쉽게 이해시킬 수 있도록 강의자료를 다듬고 다듬은 결과가 바로 이 책입니다. 강의를 하는 3년 내내 게임프로그래밍 학과 학생들이 이 과목을 AI 대학의 가장 훌륭한 수업으로 꼽을 정도였으니 (좀 부끄럽지만) 이 책을 자신있게 권해드릴 수 있을 것 같습니다. 그리고 제 과목에서 만든 데모 프로그램을 포트폴리오로 삼아서 Ubisoft 및 EA같은 세계 유수의 회사에 취직한 학생들도 몇 됩니다. 가슴 뿌듯한 일이죠. ^^

현재는 게임개발에 좀 더 집중해 보려고 대학강의를 중단한 상황이지만 이 내용을 그냥 썩혀두기엔 아깝다고 생각되어 책을 내기로 결정을 했습니다. 이 책이 쉐이더를 배우시려는 분들에게 도움이 될 수 있었으면 좋겠습니다.

이 책의 기본원칙
강의에서도 그랬듯이 이 책을 쓸 때 다음의 원칙을 기초로 삼았습니다.


  • 실습 위주: 물론 쉐이더를 짤 때 수학이나 이론을 전혀 무시할 수는 없습니다. 하지만, 이론을 먼저 배우고 그걸 코드로 옮기는 것보단 일단 코드를 좀 짜본 뒤에 뭔가 막히면 이론을 찾아보는 것이 훨씬 훌륭한 학습방법입니다. 이렇게 문제를 해결하기 위해 찾아본 이론은 기억에 오래 남습니다. 따라서 이 책은 실습위주로 구성되어있습니다. 책의 내용을 한 줄씩 따라 하면서 코드를 짜다 보면 어느덧 배경 이론까지 적당히 이해하시게 될 겁니다.
  • 쉬운 설명: 제 수업에 청강을 하러 오는 게임아트 학과 학생들도 꽤 있었습니다. 따라서 아티스트들도 이해할 수 있도록 쉽게 설명을 하는 것이 제 목표 중 하나였습니다. 그러려면 무언가를 설명할 때, 수학공식을 보여주기 보다는 실제 생활에서 일어나는 현상을 예로 드는 것이 낫더군요. 이 책을 쓸 때도 마찬가지 원칙을 따랐습니다. 책을 읽으시다 보면 100% 이론적으로 옳지 않은 설명들도 가끔 보실 겁니다. 이것은 말 그대로 설명을 쉽게 하기 위해 제가 이론들을 적당히 무시하였거나 아니면 저 조차 이론을 100% 제대로 이해하지 못하는 경우입니다. 게임 그래픽은 어차피 눈에 보이는 결과가 맞으면 그게 정답인 분야이므로 이론적으로 약간 틀려도 결과만 맞으면 전 크게 신경 쓰지 않습니다.
  • 입문자만을 위한 책: 이 책은 순수하게 입문자를 위한 책입니다. 이미 고급기법을 다루는 훌륭한 책이 많이 나와있는 상황에서 굳이 그 책들과 경쟁할 필요를 못 느끼고, 중복되는 내용을 다루면서 지면수를 늘리고 싶지도 않기 때문입니다. 이 책을 보신 후에 쉐이더에 재미가 붙으신 분들이 다른 고급기법들을 즐겁게 찾아 보실 수 있다면 전 행복합니다. 그리고 정말 괜찮은 새 기법을 찾으시면 저에게 살짝 귀뜸이라도 해주시면 더 좋겠지요. ^^
  • 순서대로 배우는 내용: 강의를 할 때 좋았던 점은 쉬운 내용부터 어려운 내용까지 순서대로 가르칠 수 있었다는 것입니다. 이 책도 그런 식으로 진행이 됩니다. 처음 장부터 시작해서 천천히 지식을 축적해간다고 할까요? 따라서 뒷장으로 가면 갈 수록 기본적인 내용은 다시 설명을 하지 않습니다. 예를 들면, 법선매핑을 배우기 전에 이미 조명기법들을 배워보므로 법선매핑에서는 조명기법에 대해 다시 설명하지 않는거죠. 따라서 이 책을 읽으실 때는 대학강의를 들으시듯이 처음부터 순서대로 읽으셔야 합니다. 이 책이 다른 쉐이더 책들처럼 여러 논문을 한군데 모아놓은 게 아니니 그 정도는 이해해주시면 좋겠습니다. 그리고 지면수도 그리 많지 않으니 무리한 요구는 아닐 거라고 믿습니다.

이 책에서 다루는 내용
이 책에서 다루는 내용은 정점쉐이더와 픽셀쉐이더를 이용한 쉐이더 기법들입니다. 이 책은 크게 세 부분으로 나뉘어져 있습니다.


  • 제1부: 쉐이더의 정의를 알아 본 뒤, 모든 쉐이더 기법의 기초가 되는 색상, 텍스처 매핑, 조명 쉐이더를 만들어 봅니다.
  • 제2부: 1부에서 배운 내용에 살을 붙여 게임에서 널리 사용하는 스페큘러매핑, 법선매핑, 그림자 매핑 등의 기법들을 구현합니다.
  • 제3부: 요즘 게임에서 점점 중요해져 가는 2D 이미지 처리 기법을 배워봅니다.


이 책에서 DirectX 10과 11에서 새로 추가된 지오메트리(geometry), 헐(hull), 연산(compute) 쉐이더들을 다루지 않는 이유는 초급자에겐 좀 어려운 내용일 뿐만 아니라 아직 실무에서 널리 이용되지 않기 때문입니다. 따라서 실용적인 내용을 알려드리기가 좀 어렵죠. DirectX 10이 처음 소개될 때만 해도 홍보자료에서는 엄청 대단한 것처럼 광고를 해댔지만 실제 실무에서 제대로 이용한 경우가 없으니까요. 일단 이 책에서 기초를 다잡으시면 몇 년 뒤에  이 내용을 배우셔도 크게 문제가 없을 겁니다.

대상독자
프로그래머
제가 가르쳤던 학생들은 게임 프로그래밍 학과 2학년 학생들이었습니다. 제 과목을 듣기 전에 C++, 3D 수학, DirectX 등을 이미 마친 학생들이었지요. 게임개발자 분들이 쉐이더 프로그래밍에 입문하는 과정도 이와 다르지 않다고 생각합니다. 최소한 DirectX는 마치신 뒤에 쉐이더를 살펴보시는 게 보통이니까요. 이 책의 대상독자도 마찬가지로 하겠습니다. 이 책을 보시려면 최소한 C++과 DirectX 정도는 공부하셨어야 합니다. 3D 수학까지 아시면 더 도움이 되겠습니다.

테크니컬 아티스트
요즘 들어 프로그래머와 아티스트 사이를 조율해주는 테크니컬 아티스트 분들의 입지가 높아지고 있습니다. 그리고 이제 테크니컬 아티스트들이 쉐이더 프로토타입을 만드는 경우도 허다합니다. 강의를 하는 도중에 일반 아티스트(청강생)들도 어느 정도 이해를 했던 내용들이니 테크니컬 아티스트 정도 되시면 아무 문제가 없으시겠지요? 테크니컬 아티스트들은 굳이 DirectX를 직접 다루지 않아도 되니 별다른 준비사항 없이 이 책을 보셔도 될 것 같습니다. (보시다 이해가 안 되는 수학 같은 게 있으시면 정석 책을 열어보시거나 인터넷 검색을 좀 하셔야 할지도 모르지만요. ^^) 각 장의 마지막에 DirectX 프레임워크를 다루는 부분이 있는데 그 부분만 건너 뛰시면 됩니다.

온라인 커뮤니티
이 책을 보시다가 궁금하신 것이 있으시면 제 블로그로 오시기 바랍니다. 토론장을 열어두겠습니다. 그 외에 정오표나 기타 업데이트들도 이 사이트를 통해 공개할 예정입니다.

http://kblog.popekim.com/

(사실 이미 제 블로그에 이 글을 올리는 마당에 정오표나 기타 업데이트들을 굳이 따로 올릴 필요가 있나 모르겠습니다. -_-)

감사의 말씀
이 책이 나오기까지 많은 분들이 도움을 주셨습니다. 이 자리를 빌어 감사의 뜻을 표현하는 것이 최소한의 도리라고 생각합니다.

우선 이 책을 쓸 수 있는 계기를 마련해주신 조진현님께 감사의 말씀을 드리고 싶습니다.

강의실에서 학생들과 직접 얼굴을 맞대면서 가르친 내용을 책으로 옮기는 건 사실 쉬운 일이 아니었습니다. 강의실 환경과는 달리 책은 일방적인 의사소통 수단이어서 과연 제가 말하고자 하는 바가 독자분들께 잘 전달이 될런지 매우 걱정이 되더군요. 이 때, 이 책의 내용과 샘플코드들을 꼼꼼히 테스트 해주신 개발자 분이 두 분 계십니다. 두 분 다 제 대상독자층에 속한 분이셨죠. 한 분은 이미 게임개발업계에 꽤 계셨지만 쉐이더 프로그래밍은 안 하셨던 분이고, 다른 분은 일반 프로그래머 일을 시작한 지 얼마 안 되시는 분입니다. 이 분들이 책을 처음부터 끝까지 꼼꼼히 읽어주시고, 코드를 한 줄 씩 직접 테스트해 주신 덕에 잘못된 내용을 최소한으로 줄일 수 있었습니다. 또한 이 분들이 보내주신 피드백에 따라 부족한 내용을 보완한 덕에 더욱 튼실한 책을 만들 수 있었죠. 유스하이텍의 이경배님과 네오플의 송진영님, 정말 많은 도움이 되었어요. 고맙습니다.

마지막으로 이 책의 준비 단계부터 블로그와 트위터를 통해 많은 관심을 가져주시고 응원해주신 전직/현직/미래 게임개발자 분들과 일반인(?) 분들께 감사의 말씀을 드리고 싶습니다. 강다니엘, 고경석, 김동환, 김성완, 김영민, 김정현, 김혁, 김호용, 박경희, 박수경, 손기호, 신성일, 안진우, 유영운, 이경민, 이상대, 최재규 님, 책 나왔어요~~~



2011년 3월 캐나다 밴쿠버에서
포프 올림



2011년 11월 17일 목요일

최적화된 오렌-네이어 쉐이더 코드



이번에 KGC 2011에서 강연하면서 기존에 있던 것보다 빠른 오렌-네이어 쉐이더 코드를 공개했었습니다. 강연자료를 다 보기 귀찮으신 분들을 위해 그 코드만 빼서 여기에 올립니다. 저희가 이전에 쓰던 오렌-네이어 코드는 Wolfgang Engel 아저씨의 위키책에서 빌려왔던 거라 강의전에 Wolfgang아저씨에게 이런 코드를 만들었다고 귀뜸해주니 좋아하시더군요.

이 근사치(approximation)를 구하는 코드의 장점은 텍스처 룩업을 하지 않는 다는 것이죠. 스페이스마린에서는 텍스처 룩업이 보틀넥이었거든요. 일단 이 코드는 수학적으로 100% 맞는건 아니지만 저희 겜에서는 아무 문제 없이 썼습니다. (강연중에도 말씀드렸듯이... '수학적인 검증은 중요치 않다. 아티스트들 보기에만 맞으면 된다.')


half ComputeOrenNayarLighting_Fakey( half3 N, half3 L, half3 V, half roughness )
{
  // Through brute force iteration I found this approximation. Time to test it out.
  half LdotN = dot( L, N );
  half VdotN = dot( V, N );
  half result = saturate(LdotN);
  half soft_rim = saturate(1-VdotN/2); //soft view dependant rim
  half fakey = pow(1-result*soft_rim,2);//modulate lambertian by rim lighting
  half fakey_magic = 0.62;
  //(1-fakey)*fakey_magic to invert and scale down the lighting
  fakey = fakey_magic - fakey*fakey_magic;
  return lerp( result, fakey, roughness );
}



2011년 11월 16일 수요일

"스페이스마린의 렌더링 기술" 슬라이드 공개합니다.

KGC 2011에서 강연했었던 "스페이스마린의 렌더링 기술"의 슬라이드를 공개해도 된다는 허락을 드디어 받았습니다. 아래 링크를 누르시면 보실 수 있습니다.

2011년 11월 15일 화요일

제 KGC 2011 강연 피드백들...

이번엔 "스페이스마린의 렌더링 기술"이라는 주제로 직장동료 다니엘 바레로 박사님과 함께 KGC 2011에서 강연을 했습니다. 어떻게 봐주셨나 궁금해서 웹 검색을 좀 해봤는데 다행히 반응들이 좋네요. 제가 찾은 반응들 링크 걸어 놓은 것 입니다.

1. http://agebreak.blog.me/60146508810

그래픽스 관련 강연을 주로 많이 들었는데, 괜찮은 강연들이 꽤 많았습니다. 새로운 기술을 설명하는 강연부터, 상용화된 게임에서 어떻게 적용하는지에 대한 내용들이 괜찮았습니다. 특히나 워해머 강연은.. 강추…ㅠ.ㅠ (자세한 내용은 다음 글에…)

2. http://twitter.com/#!/TranosTria/status/133826484547764224

kgc 1일차 2일차를 통 틀어서 워해머 스페이스 마린의 렌더링 기술 섹셕이 가장 좋은 세미나가 아닌가 싶다. 특히 "우린 수학적인 검증따윈 신경안쓴다. 오직 룩만 좋으면 그걸로 끝이다"라는 얘기가 무한 공감간다 ㅋㅋㅋ

3. http://beaumale.blog.me/80144986487
...해외 유명게임 개발자가 와서 강연해 주고 있는데(클라 프로그래머라면 누구든 꿈꾸는 그런 인물!) 맨 앞자리에서 쳐 졸고 있질 않나...(그래, 워해머40K 스페이스마린 렌더링 기술 강연때 맨 왼쪽 앞에 앉은 너희 두놈) 밖에서 받은 기념품 봉지를 뽀시락거리면서 신경 거슬리게 하지 않나...
4. http://m.inven.co.kr/powerbbs/powerbbs.php?come_idx=2813&l=38
... 꼭 듣고 싶은 강의는... 11월 8일... 16:30~18:40 = 스페이스 마린의 렌더링 기술

5. http://blog.naver.com/taiger11/20141997930
제가 존경하는 게임개발자이신 포프님입니다 ㅇㅂㅇ.... 처음엔 게임개발에 관심가지고 정보 찾아보다가 포프님 블로그에서 북미게임기업취업에 대해 다루는 글을 보게 되었고 댓글을 달면서 소통하다가 알게된분이심. 작년엔 일이있으셔서 KGC 강연에 참가 못하셨는데 올해는 KGC에 참가하시네요 ㅇㅂㅇ ....(프로그래밍 잘 못하지만 가고싶은...근데 수능이랑 겹치지 ㅋㅋ OTL) 나도 커서 포프님처럼 남들앞에서 떨지않고 뭔가 발표하거나 강연해보고 싶은...
6. http://media.daum.net/society/nation/others/view.html?cateid=100011&newsid=20110929141208516
다니엘 베리노 렐릭엔터테인먼트 프로그래머와 킴 포프 수석 그래픽 프로그래머도 공동연사로 나선다. 둘 다 게임엔진과 게임그래픽 분야의 대가다.