꽃미남 프로그래머 김포프가 창립한 탑 프로그래머 양성 교육 기관 POCU 아카데미 오픈!
절찬리에 수강생 모집 중!
프로그래밍 언어 입문서가 아닌 프로그래밍 기초 개념 입문서
문과생, 비전공자를 위한 프로그래밍 입문책입니다.
jobGuid 꽃미남 프로그래머 "Pope Kim"님의 이론이나 수학에 치우치지 않고 실무에 곧바로 쓸 수 있는 실용적인 셰이더 프로그래밍 입문서 #겁나친절 jobGuid "1판의내용"에 "새로바뀐북미게임업계분위기"와 "비자관련정보", "1판을 기반으로 북미취업에 성공하신 분들의 생생한 경험담"을 담았습니다.
Posted by 비회원
저는 정식 애니메이션 교육을 받은 적이 없지만 실무에서 애니메이션 작업을 해야 했고 후배 애니메이터들의 결과물을 컨펌해야 했었습니다. 최근에는 애니메이션 컨펌을 할 일이 거의 없었고 마지막으로 애니메이션 작업을 한건 거의 10년도 넘은 오래 전의 일이네요.

이것은 마치 무면허 의사에게 치료를 맏기는 상황이지만 과거에는 모든 상황이 열악했습니다. 요즘은 인터넷, 책, 교육기관 등을 통해서 제대로 된 교육을 받을 방법이 정말 많아졌죠. 멘토 혹은 누군가에게 질문이라도 할 수 있는 사람이 내 주변도 아니고 업계 어딘가에 있다는 사실이 얼마나 좋은 환경인지 요즘 개발자들은 피부로 느끼지 못할 것 같네요.

이런 이유로 - 무면허 돌팔이 애니메이터였기 때문에 - 제가 최근까지 애니메이션에 대해서 잘못 알고 있었던 사실 한 가지를 공유하려고 합니다. 세컨더리 액션에 대한 오해인데요, 최근 집필했던 '게임 개발자를 위한 캐릭터 셋업 테크닉' 이라는 책에서 세컨더리 액션(혹은 애니메이션)에 대해 언급할 때에도 오해를 하고 있었던 부분입니다. 그리고 얼마가 될지 모르겠으나 현직 애니메이터들 중에서도 잘못 알고 있는 분들도 좀 있을 것으로 생각됩니다.

어떤 부분을 잘못 알고 있었는지 결론부터 먼저 살펴보겠습니다.

Before : 세컨더리 액션은 2차적인 혹은 부가적인 애니메이션이다. 사람이 움직일 때 흔들리는 각종 부속물들이 그것이다. 예를 들면 머리카락, 귀걸이, 옷 소매, 치마 등 캐릭터의 관절 움직임에 대해서 물리적인 사실감을 높여주는 애니메이션 장치이다. 기본 관절 애니메이션은 세컨더리 액션에 포함하지 않는다.

After : 세컨더리 액션은 프라이머리(Primary) 액션을 도와주는 모든 액션을 말한다. 캐릭터에 부속물이 전혀 없는 상태에서도 세컨더리 액션이 있을 수 있다. 기본 바이패드만으로도 세컨더리 액션이 있을 수 있다는 뜻. 예를 들어 캐릭터가 벌거벗고 추위에 떨고 있다면 웅크린 자세는 프라이머리 액션이며 부들부들 떨리는 연출이 세컨더리 액션이다.

After 에서 정의하는 세컨더리 액션은 더 범위가 넓은 개념입니다. Before에서의 덜렁거리는 부속물들 역시 After 안에 포함됩니다.

이런 생각의 변화는 의외의 곳에서 생겼습니다.

최근 초보 애니메이터들을 위한 교육 자료를 준비해야 하는 일이 있었는데요. 디즈니 애니메이션의 12원칙에 대해 자료를 찾다가 DIgital Tutors 라는 사이트에서 만든 튜터리얼 컨텐츠를 YouTube 에서 발견하게 되었고 초보 애니메이터에게 상당히 좋은 자료라고 판단되어서 자막 번역을 하기로 결심했었습니다. 자막 번역 작업은 처음인데다 영어에 서툴러서 생각보다 무척 어려운 작업이더군요. 전체 22편 분량의 튜터리얼인데 얼마 전 10편까지 자막 작업을 마쳤습니다. 10편의 주제가 세컨더리 액션이였는데 번역을 하면서 기존에 알고있던 세컨더리 액션의 개념보다 더 광범위한 개념이라는 것을 발견하게 되었습니다.

관련 동영상 링크 : Removing the Confusion of Secondary Action

(번역한 자막 파일도 첨부했습니다)

사실 업계 용어의 정의는 문화권이나 플랫폼에 따라서 조금씩 달라지는 경우가 많아서 특정 단어를 잘못 이해하고 있는게 크게 문제되는건 아닙니다. 가장 중요한건 멋진 애니메이션을 만들 수 있는 감각과 열정입니다.

마치기 전에 번역 작업을 진행하고 있는 포스팅 링크를 공유합니다.
http://cafe.naver.com/pinksox/3546
이곳에 나머지 튜터리얼의 자막들이 있습니다. 제가 영어에 서투른데다 강사분의 말이 워낙에 빨라서 여기 저기 오역이 많을 것으로 생각됩니다. 잘못 번역된 부분이 보이면 꼭 알려주시기 바랍니다. 그리고 틈틈히 번역하고 있긴 하지만 생각보다 양이 무척 많네요. 나머지 분량의 자막 작업을 혹시 도와주실 분이 있으면 꼭 연락 주세요. pinksox@nate.com 입니다.

감사합니다.
TAG 핑속

댓글을 달아 주세요

Posted by 비회원

메모리 최적화에 대한 이슈는 게임 개발자에게 굉장히 민감한 주제 중에 하나 입니다.
특히나 게임 개발에서 메모리를 가장 많이 차지하는 것은 텍스쳐입니다.
지금부터 언급되는 텍스쳐는 DirectX9 에서 POOL_MANAGED 옵션으로 생성되는
Managed-Texture 형태의 텍스쳐로 국한합니다.
( 텍스쳐 관리 시스템에서 제어되는 텍스쳐는 POOL_MANAGED 옵션을 가진 텍스쳐 뿐입니다. )

게임개발자가 텍스쳐를 사용하는 동작을 제가 아래와 같이 단순화 시켜보았습니다.

먼저 우리가 원하는 텍스쳐를 메모리에 로드할 수 있습니다.
비디오-메모리에 직접적으로 로드할 수 있으며, 시스템-메모리에 로드할 수도 있습니다.
로드할 때, 우리는 메모리를 조금 더 최적화하기 위해서
DirectX 에게 여러가지 힌트 옵션을 설정하기도 합니다.
이런 힌트 옵션들은 DirectX의 여러 버전들마다 설정 방법이 조금씩 다르지만,
기본적으로 내용은 비슷합니다.( 읽기전용/쓰기 전용 등이죠... )

그리고 필요해 위해서 DirectX 의 상태를 변경해서 텍스쳐를 그래픽 파이프라인에 연결합니다.
SetTexture( ... ) 같은 API 들이 이런 역할을 합니다.

마지막으로 필요하지 않는 텍스쳐는 직접 제거를 해줍니다.

결국 개발자가 할 수 있는 것은 Load-->Bind-->Release 의 형태 뿐입니다.
게임을 하는 중에 비디오-메모리가 가득차 있는데,
새로운 텍스쳐가 로드되면 어떤 상황이 벌어질까요?
새로운 텍스쳐를 로드하기 전에 비디오-메모리의 사용 가능한 공간을 체크한 후에,
새로운 텍스쳐를 로드하면 간단히 해결할 수 있습니다.
하지만 지금 우리는 개발할 때, 그런 체크를 하지 않습니다.

이 상황으로 유츄해 보면, 누군가에 의해서 자동적으로 어떤 작업이 이루어지고 있습니다.
그 누군가가 바로 DirectX의 텍스쳐 관리 시스템입니다.
게임 개발자에게 주어진 권한은 텍스쳐의 메모리의 생성과 제거 정도에 지나지 않습니다.
그 이외에 나머지 처리는 모두 DirectX의 텍스쳐 관리 시스템에 의해서 제어됩니다.
이 텍스쳐 관리 시스템은 DirectX6 부터 도입되었습니다.
즉, 이전까지는 아마도 개발자들이 직접 메모리를 계산하면서 처리했을 겁니다.
( 아마도~~ㅎㅎ )

이런 텍스쳐 관리 시스템은 기본적으로 다음과 같은 동작을 합니다.
- 현재 사용 가능한 텍스쳐 메모리의 양을 체크하고 추적
- 현재 렌더링 작업을 위해서 필요한 텍스쳐와 그렇지 않은 텍스쳐를 결정
- 비디오-메모리에 있는 텍스쳐 중에 어떤 것이 제거되어야 하는지를 결정
- 시스템-메모리에서 다시 읽어들일 텍스쳐를 결정

사실 이것보다 더 많은 작업을 하겠지만, 제가 이 정도로만 간략화 시켜보았습니다.

텍스쳐 관리 시스템은 여러 결정권을 가지고 있습니다.
특히나 비디오-메모리에서 제거 권한은 우리 개발자에게 정말 두려운 권한입니다.
힘들게(?) 비디오-메모리에 올려두었는데,
시스템에서 자기 마음대로(?) 그냥 내려버리면 얼마나 가슴 아프시겠습니까?

그래서 이런 가슴 아픈 일을 방지하는 차원에서
텍스쳐들에게 우선 순위를 부여할 수 있습니다.
텍스쳐 관리 시스템은 일정한 규칙을 가지고 비디오-메모리에서 텍스쳐를 제거합니다.
그 규칙이라는 것은 기본적으로 LRU( least-recently-used ) 에 기반을 두고 있습니다.
이는 비디오-메모리가 가득차 있는 상태라면,
이들 중에 비디오-메모리에서 제거가 되는 것은
가장 오랫동안 사용되지 않은 텍스쳐라는 것을 의미합니다.

개발자들은 비디오-메모리의 부족에 고통을 호소합니다.( 저만 그런가요? ㅎㅎ )
비디오-메모리가 가득찬 상태에서 새로운 하나의 텍스쳐가
비디오-메모리로 로드된다고 가정하겠습니다.
그러면, 텍스쳐 관리 시스템은 LRU로 체크를 해서
하나의 텍스쳐를 비디오-메모리에서 제거할 것입니다.
그리고 새로운 텍스쳐를 비디오-메모리로 로드할 것입니다.
실제로 텍스쳐 관리 시스템은 이것보다 훨씬 복잡한 방법으로 동작할 것입니다.
( 예를 들기 위해서 텍스쳐 크기 같은 문제를 제외하고 예를 드는 것 뿐입니다. )

이런 상황에서 10개의 새로운 텍스쳐가 비디오-메모리로 로드된다고 생각해 보십시오.
시스템-메모리에서 비디오-메모리의 데이터 전송이 최소 10번이 이루어져야 합니다.
또한 최소 10번 이상의 비디오-메모리에서 제거할 텍스쳐를 결정하는 작업이 이루어져야 합니다. 
이것이 많아지면, 병목 현상을 초래할 수 있습니다.
이것은 텍스쳐 스레싱( texture thrashing ) 이라고들 합니다.

실제 게임 플레이 중인 상황에서 갑자기 새로운 배경이나 오브젝트들이 등장할 때
프레임이 느려지는 현상이 발생하게 되는데, 이런 작업도 거기에 영향을 미치는 요소입니다.
게임이 실행 중인 경우에는 이미 많은 비디오-메모리를 사용 중이니,
사실 빈번하게 발생할 수도 있는 일입니다.
무책임한 말일 수 있으나, 이것은 어쩔 수 없는 일입니다.
( 적절히(?) 개발자들이 노력해야 할 부분이죠? ㅎㅎㅎ )

그런데 비록 오래 사용되지는 않았지만,
무척이나 중요한 텍스쳐가 있으면 조금 문제가 되지 않을까요?
반드시 비디오-메모리에 있어야 할 텍스쳐라는 개념이 아닙니다.
( 만약 반드시 비디오-메모리에 있어야 한다면 POOL_DEFAULT 로 직접 관리해 주시면 됩니다.)

텍스쳐 관리 시스템에서 비디오-메모리에서 제거할 목록들을 구성할 때 
일종의 특혜(?) 가 있는 텍스쳐들은 제거 목록에서 제외시켜달라는 의미로 볼 수 있습니다.
이것은 비디오-메모리에 계속해서 남아있을 필요는 없지만,
되도록이면 조금 더 오래 남겨달라는 의미로 해석하실 수 있습니다.
이렇게 특혜(?)를 부여하는 것이 바로 우선 순위를 설정하는 작업입니다.
비디오-메모리에서 제거될 후보군들 중에서 LRU 값이 같다면,
우선 순위가 낮은 텍스쳐가 제거되는 것입니다.

IDirect3DResource9 라는 인터페이스를 상속받아서
Direct3D의 텍스쳐 인터페이스가 만들어졌습니다.

IDirect3DResource9 인터페이스는 이 우선 순위를 설정할 수 있는 멤버함수를 가지고 있습니다.
IDirect3DResource9::SetPriority( ... ) 가 바로 그것입니다.
Managed-Texture 의 경우 기본적으로 우선 순위가 0 입니다.
0보다 높은 숫자를 입력하면, 높은 우선 순위가 됩니다.
그런데 무턱되고 높은 숫자를 입력하면, 문제의 소지가 있을 수 있습니다.
그래서 이를 상수로써 정해진 몇몇 값들이 있습니다.
그 값들은 아래와 같습니다.

D3D9_RESOURCE_PRIORITY_MINIMUM 0x28000000
D3D9_RESOURCE_PRIORITY_LOW 0x50000000
D3D9_RESOURCE_PRIORITY_NORMAL 0x78000000
D3D9_RESOURCE_PRIORITY_HIGH 0xa0000000
D3D9_RESOURCE_PRIORITY_MAXIMUM 0xc8000000


이것은 DirectX가 스케쥴링 목적으로 정의한 상수들입니다.
이 우선 순위를 그대로 텍스쳐에 적용하시면 안됩니다.
일반적으로 텍스쳐의 경우 D3D9_RESOURCE_PRIORITY_NORMAL 우선 순위를 사용해야 합니다.
그리고 아래와 같이 설정하는 것이 좋습니다.

ManagedTex->SetPriority( D3D_RESOURCE_PRIORITY_NORMA + 1 ); 
ManagedTex->SetPriority( D3D_RESOURCE_PRIORITY_NORMA + 2 );
ManagedTex->SetPriority( D3D_RESOURCE_PRIORITY_NORMA + 3 );


Managed-Texture는 실제로 렌더링 작업이 이루어지기 전까지
비디오-메모리에 데이터가 존재하지 않습니다.
렌더링 작업이 한번이라도 이루어져야 할 때,
시스템-메모리의 텍스쳐 메모리가 비디오-메모리로 전송이 됩니다.
이것도 바로 텍스쳐 관리 시스템이 하는 작업 중에 하나입니다.
그런데 텍스쳐를 로딩하고, 이를 비디오-메모리에 바로 올리고 싶은 경우가 있을 수 있습니다.
이미 텍스쳐를 로딩한다는 것 자체가,
바로 렌더링 작업에 사용할 것이라는 확신이 있는 경우일 것입니다.
그 때는 IDirect3DResource9::PreLoad() 를 사용하시면 됩니다.
그러면 약간의 성능 향상을 보일 수도 있습니다.
( 이것은 저도 아주 약간의 효과를 경험했었습니다.^^ )

게임을 플레이 중에 씬 전체가 새로운 텍스쳐들로 가득 채워져야 하는 경우는 없으셨나요?
그런 경우 텍스쳐 스레싱 현상이 아주 크게 느껴질 수도 있습니다.
그래서 한꺼번에 비디오-메모리를 모두 비워버리는 API가 있습니다.
IDirect3DDevice9::EvictManagedResource() 가 바로 그것인데,
이 API는 보시다시피 Device 인터페이스의 API 입니다.
즉, 버퍼와 텍스쳐를 포함한 Managed 리소스까지 모두 비디오-메모리를 비워버립니다..
그래서 씬이 완전히 새롭게 구성될 때, 꽤 유용할 수 있습니다.
( 저는 이 API 아주 좋아합니다..ㅎㅎㅎ )

DirectX9 의 텍스쳐 관리 시스템은 사실상 이 세가지 API를 통해서 제어를 합니다.
나머지는 우리 개발자의 손을 떠난 문제입니다.
위의 문제를 고민하기 전까지 저는 게임에 사용되는 메모리를 계산해 본 적이 없었습니다.
예를 들면 상점이나 특정 지역에서 사용되는 메모리 계산이겠죠.
게임 프로그래머가 단순히 주어진 리소스를 렌더링만 한다는 개념에서
벗어나게 해주었던 작업들이였습니다.
 
TAG 조진현

댓글을 달아 주세요

Vertex Compression

프로그래밍 2011. 12. 12. 02:00
Posted by 비회원
예전에 개인 블로그에 적은 적이 있기는 한데, 다시 한번 정리해서 올려보겠습니다. 
이전에 Nebula3 라는 공개용 엔진을 참 많이 봤었는데, 그 엔진 기능 중에 Vertex Component Packing 이라는 제목의 관심 있는 포스팅이 하나 있었습니다. 말 그대로 버텍스의 사이즈를 줄여보자는 것입니다. 버텍스 사이즈를 줄임으로써 얻는 이득이 몇 가지가 있는데요.
- 첫째, 게임에서 mesh 리소스의 사이즈를 줄일 수 있습니다. 이게 별거 아닌 것 처럼 느껴지겠지만, 게임을 릴리즈 할 때 정도 되면, 엄청난 양의 리소스 데이터를 줄일 수 있다는 이야기가 됩니다.
- 두번째, 전체적이 로딩 시간을 줄일 수 있습니다.
- 세번재, 전체적인 버텍스 버퍼의 크기를 줄여주기 때문에, 그래픽 카드로 버텍스 데이터를 전송할 때, 버텍스 처리량(vertex though-put)이 좋아집니다.

물론, 추가적인 shader에서 연산이 들어갑니다. 하지만, 얻어지는 이득과는 Trade-Off 관계이기 때문에, 상황에 맞게 선택을 하면 되겠습니다.

Vertex 압축

패킹된 버텍스 구조의 최종 모습은 이렇습니다.

[Nebula3]

각 Comonent이 가지는 특성을 이용해서, 값의 범위에 따라 적절하게 값을 압축하는 형태입니다.


* Position
Position의 경우, 비교적 높은 정밀도와 표현 가능한 값의 범위가 굉장히 광범위 하게 때문에, 사실 압축을 하기란 쉽지가 않습니다. 따라서, 일반적으로 포지션 압축은 사용하지 않습니다.
 
*Texture Coord
텍스쳐 좌표의 경우, [0, 1] 사이의 범위를 가지고, 일반적인 텍스쳐의 경우에는 정밀도가 매우 중요한 편이 아닙니다. 따라서, Texture 좌표의 경우에는 압축을 시도해볼 만 합니다. float을 고정 소수점(Fixed Point)로 변환하여, float2 -> short2로 변환을 합니다. 이렇게 되면, 8Byte의 값을 4Byte로 변환을 할 수 있습니다. 4.12 Fixed Point 변환을 주로 이용하는데, 16비트 중 12비트를 왼쪽으로 이동시키는 것입니다. 혹은 4096으로 나누어 준다고 하면 빠르겠군요. 즉, c++에서 4096으로 나누어 주고, shader에서 4096을 곱해주어서 복원해주는 형태입니다.

- Normal/Tangent/Binormal :
노말은 [-1, 1]의 범위를 가지고 있고, 정밀도 또한 그렇게 중요한 편은 아닙니다. 이는 UBYTE4를 이용하면, 좋은데요. UBYTE4 계열의 특성에 대해서 먼저 알아보자면,

- UBYTE4 : 0 ~ 255 범위의 unsigned char형 4개 (BGRA)
- UBYTE4N : 0 ~ 1 범위의 unsigned char형 4개 (BGRA)
(geforce 7xxx 이상의 그래픽 카드에서부터 지원!!!) 
 

Normal의 경우에는 UBYTE4N을 사용합니다. 이 결과, 12Byte(float*3) -> 4Byte(ubyte4n)으로 줄일 수 있습니다.  http://www.gamedev.net/topic/491408-how-to-design-a-mesh-class-/ 를 참고하시면, 어떻게 압축을 하는지 코드를 보실 수 있습니다.

- Skin Weights
Skin Weight의 경우, [0~1] 사이 범위의 값을 가지기 때문에, 이는 UBYTE4N 형을 사용해서 압축을 하면, 그대로 이용이 가능한 범위입니다. 이를 통해서 float4(16byte)를 UBYTE4N(4byte)로 줄일 수 있군요. 하지만, 이 경우, 정밀도가 영향을 줄 수 있기 때문에, 셰이더에서 다시 한번 정규화를 해주어서, 전체적인 weight를 보정해줍니다.
기본적으로 normal과 동일하게 처리가 되지만, [0, 1]의 범위이기 때문에,  노말과 같이 [-1, 1] -> [0, 1]로 변환해주는 과정 (normal * 0.5f + 0.5f)을 할 필요가 없이 바로 UBYTE4N로 변환을 할 수 있습니다.

return (packedWeights / dot(packedWeights, float4(1, 1, 1, 1)));


- Skin Index
Skin 의 본 인덱스의 경우, [0, n]의 값 범위를 가지게 되는데, bone의 개수가 255를 넘지 않는다며, UBYTE4의 특성을 이용해서, 압축이 가능합니다. 이 결과로 float4(16byte)를 ubyte4(4byte)로 압축이 가능합니다.

이 결과 버텍스 하나가 position(float4), normal(float3), uv(float2), skinweights(float4), skinindices(float4)로 구성되어 있을 때, 압축을 하면, 64Byte -> 28Byte로 버텍스의 사이즈를 줄여줄 수 있습니다. 

결론
 최근 온라인 게임의 리소스 데이터의 용량이 1G가 넘어가는 경우는 이미 일반적입니다. 이러한 상황에서, 리소스 데이터를 다운로딩하는 시간을 줄이는 것 또한 많은 개발사에서 고민을 하고 있습니다. 특히, 해외 서비스를 하는 경우에는 더욱이 이러한 필요성을 더욱 많이 느끼고 있습니다.
이런 고민의 해결책 중 하나가 vertex 압축이 될 수도 있습니다. 약간의 vertex shader 추가적인 연산을 통해서, 데이터 사이즈를 1/3 정도로 줄일 수 있다면, 충분히 시도해볼만한 작업이라고 생각합니다.
 

참고자료
- http://cagetu.egloos.com/4941476
- http://zho.pe.kr/view.html?file_name=doc/vtxprg.txt
http://flohofwoe.blogspot.com/2008/03/vertex-component-packing.html
TAG cagetu

댓글을 달아 주세요

Posted by 비회원
제가 해왓던 일과 하고 있는 일이 모두 컨셉디자인 또는 그래픽 디자인 쪽이기 때문에 제가 10년정도 개발을 하고 공부하면서 개인적으로 도움이 되었던 부분에 대하여 간략하게 정리하는 차원으로 포스팅을 해봅니다. 지극히 초보적인 관점에서 바라보는 시각이니 뭘~~이런걸~~이라고 하실수도 있겠지만 몇몇 그래픽 디자이너들은 이런거에 많은 관심을 두거나 전문적인 지식없이 접근하는 부분이 의외로 많이 있더군요(제경험상으로 비추어 봤을때...입니다 ㅜ.,ㅜ)-잘하시는 분들이야..뭐. ^^; 

예전에 아무것도 모를때 (그림을~) 맨땅에 해딩하던 그시절 좀더 화면 자체의 느낌이나 그런걸 컨트롤 할수있는 툴(포토샾과 비슷하지만 뭔가다른) 그런 툴이 있으면 좋겠다라고 생각햇습니다. 제가 워낙 실력이 부족했던 터라 더욱더 간절 햇지요. 이론적으로 아는것과 실제 적용은 차이가 많지요, 그림도 마찬 가지인것 같습니다.



뭐 물론 그림을 잘그리시는분들은 그냥 그려내시지요, 화면의 밝기 톤을 자유 자제로 조절하여 빛의 양을 조절하며 그어렵다는 GI 의 표현을 손으로 사실적으로 묘사하시는 분들이 매우 많으니까요. 단순히 제 실력이 부족하여 꽁수를 부리며 말이죠.



그림자체도 알고보면 매우 과학적이고 공식이 있지요...공식으로 커버 할수 없는 감각이란 부분이 있지만 색배열이라던가 상황에 따른 묘사...음...뭐랄까 프로그램에서의 그래픽스를 손으로 한땀 한땀(?) 손으로 그려내는 느낌으로 생각하시면 될것 같습니다.



엔진에서 렌더링을 통해 실제 보여지는 이미지를 만들기위해 많은 노력이 필요하듯 그림도 최종 결과물을 좋게만들기위해서는 일일이 빛계산과 색,그림자 등을 신경쓰는것과 안쓰는것의 차이는 무지 큽니다.일반적으로 프로그래머들은 열심히 코딩을 하시면서 하나씩 쌓아 가시는것 처럼 그림 1장을 그릴때는 항상 처음부터 그 생각의 정리들을 하나씩 풀어 나가지요 .

특히 사실적인 묘사가 필요한 그림들은 주변 환경 과 빛을 매우 잘 표현해줘야 멋진 그림이 나옵니
다. 네 너무 나도 당연한 이야기지만 이게 익숙하지 않거나 감각적인 사람이 아니면 의외로 힘듭니다.




예를들자면
(실제 남의 작품을 잘한다 초보다라 언급하기가 뭣하여 예시 사진으로 설명을 드립니다.ㅜ.ㅜ)


위 사진은 빛의 양을 맘대로 손으로 표현할수 없는 초보들이 흔히 하는 실수와도 비슷한거라 올려봅니다.밝은 부분만 열심히 묘사하는것이지요...어두운 부분은 어두우니 대충....그립니다..색도 중요하지않습니다..그냥..어두우니까 어둡게 색도 무지 탁하지요... 위 사진보다야 묘사들이 조금은 있겠으나 그 묘사또한 빛의 바운스를 많이 고려하지 않고 주변 환경빛을 고려하지 않는 묘사가 많이들 들어가곤 합니다.(묘사가 없다거나 빛의 방향이 틀리거나 색이 이상하다거나...) 물론 저느낌이 12시 정오 대낮 아주 밝은 날이였을때 거나 ..아메리칸 코믹스의 느낌으로 어두운 부분을 확 날려주는 느낌으로 접근하는 그림이라면 나름 분위기가 잘 살수도 있으나 사실적인 느낌의 그림이라고 하면 별로 지요 . 프로그램적 그래픽스로 따지면 GI 의 효과가 없는것과도 같은 느낌의 그림이지요...


그렇다면  위의그림이 초절정 고수들의 그림이 되겠네요..생각보다 저런느낌을 잘 표현 해서 그리는게 쉽진 않습니다.밝은톤부터 어두운부분까지의 발런스.. 바운싱돼서 물제에 투과되는 빛의 느낌까지 너무나도 사실적이며 보기가 좋습니다.  주변 환경 에 의한 빛의 색느낌또한 매우 좋습니다.


이런식으로 과학적으로 접근을 하는것은 개인적으론 좋은 접근 이라고 판단이 듭니다. 이외에 과학적으로 접근해야 하는  부분이 그림에는 너무나도 많이 있습니다. 감각을 중요시 하는 것또한 그림의 묘한 매력입니다만 특히 요즘 게임이나 영화의 컨셉디자인은 사실이 아닌것을 사실로 접근하기위해 가이드 라인을 만들어주는 역활을 하기에 좀더 과학적 접근을 통해 그린다면 아마도 조금이나마 그래픽스를 하시는 프로그래머 분들 뿐만 아니라 여러사람과 좋은 이야기, 도움이 많이 되는 이야기를 나눌수 있지 않을까 생각합니다.


역으로 그림을 잘 모르시는 분들도 '이런부분을 이해하고 접근하는 구나 이사람은~~'이라고 조금은 과학적인 사람이라고 판단하셔도 될듯 합니다 ^^ 보통 그림그리시는 분들이라하면 꾀팍하고 뭐랄까 예술적이라고 생각하실지 모르겠으나 의외로 객관성을 가지고 사물을 바라보시는 분들도 꾀나 많이 있더군요.(사실 저는 감성적인 부분은 전혀 없습니다..ㅜ.,ㅜ이론을 공부하고 그걸 실제 트레이닝을 통해 차곡차곡 쌓아가는 연습을 많이 하는 편입니다.)

실제로 저도 조금 경력이 쌓이고 이런부분에 관심을 가진이후론 자료도 찾아보며 실제 게임 그래픽을 바라보는 시점이 많이 달라 졌습니다. 그래픽스를 하시는 프로 그래머 분들과 가변운 이야기 정도는 나누게 되더군요. 제가 먼져 이런건 어떻게 구현을 할수있을지에 대해 물어보고 찾아보고 그림과 게임의 씬을 하나로 보고 접근하는 일도 종종 생기구요. 반대로 프로그래머 분들이 후처리나 이런것을위해 그림을 보정하는 2디 방식을 궁금해 하기도 하더군요..

이래 저래 알아두고 좀더 과학적인 접근을 통하여 이미지를 바라보는 습관은 좋은것 같습니다.
게임의 씬과 그림과의 차이는 코딩으로 푸느냐 눈과 손으로 그리느냐의 차이가 큰것이지 나머지는 비슷한 부분이 많은것 같습니다...



다음번엔 위와 같은 주제로 그림을 그릴때 도움이 되는 생각들~!!! 역으로 그림을 이해할때 도움이 되는 생각들에 대해 느낀대로 정리해 보도록 하겠습니다.

TAG 귀거리

댓글을 달아 주세요

Posted by 김포프
콘솔게임 개발의 장점은 한 하드웨어에 특화된 최적화를 할 수 있다는 겁니다. 마이크로소프트나 소니 둘 다 자기네 하드웨어가 더 뛰어나다는 걸 보여주기 위해 조금씩 다른 기능들을 추가하곤 하는데요. 아무래도 그래픽스 프로그래머인 저는 그래픽 관련 쪽의 하드웨어를 주로 다루게 됩니다. 여기서 간단히 설명 드릴 건 Xbox 360의 EDRAM과 PS3의 ZCull 메모리에 대해... 요즘 Darksiders 2게임 최적화 해주다보니 나름 요놈들을 주물러 줄 일이 있어서......

Xbox 360의 EDRAM
일단 Xbox 360의 EDRAM은 렌더타겟 위에 픽셀을 뿌려주는 속도를 빠르게 하기 위한 놈입니다. 보통 렌더타겟 설정하고 메쉬들을 그리면 최종 결과가 렌더타겟하고 연계된 텍스처의 메모리로 들어가잖아요? 근데 bandwidth가 충분치 않아서 여기서 bottleneck이 걸리는 경우가 많습니다. Xbox 360는 이 문제를 해결하려고 EDRAM이란 것을 렌더링 파이프라인 젤 마지막에 설치해서 텍스처 메모리가 아닌 이 하드웨어 메모리에 모든 픽셀들을 그립니다. 즉 렌더타겟 아무리 설정하고 픽셀을 수만개를 그려봐야 최종 텍스처의 메모리에는 아무것도 안들어갑니다. 모든 건 고스란이 EDRAM안에 있죠. 이러면 아무래도 EDRAM 하드웨어 상에서 블렌딩이며 overdraw며 다 처리해서 확실히 빠릅니다. 이렇게 그릴거 다 그린 뒤에 이 EDRAM 안에 있는 최종결과를 텍스처로 옮겨갈 때 쓰는 명령어가 Resolve()입니다.  XNA 개발해보신 분들은 3.0버전인가부터 Resolve()를 직접 호출해줘야 하죠? 바로 Xbox 360하고 PC에서 공통으로 실행되는 API를 제공하기 위해서 그런 겁니다.

근데 문제는 Xbox 360에서는 언제나 EDRAM을 이용해야만 한다는 거죠. 물론 EDRAM을 사용해서 성능상 손해될 것은 없습니다. EDRAM을 사용하지 않는 것보다 성능이 나오지 않는 경우는 없으니까요. 정말 문제는 EDRAM의 크기가 10MB라는 건데요. 총 합이 10MB 를 넘는 렌더타겟들을 한 번에 사용하려면 그대로 뻗습니다......이게 바로 스페이스마린 Xbox 360의 해상도가 진정한 720P가 아닌 이유입니다. 진정한 720P는 1280 X 720 픽셀을 지원해야 하는데 이럴경우 저희 조명패스가 10MB 제한을 넘었거든요.

조명패스에서 사용하는 렌더타겟:

  • 렌더타겟
    • 포맷: A16R16G16B16
    • 바이트 / 픽셀: 8바이트
  • 깊이/스텐실 버퍼 
    • D24S8
    • 바이트 / 픽셀: 4바이트
이걸 1280 X 720으로 메모리 사용량을 계산하면

  • 렌더타겟: 1280 X 720 X 8 = 7,372,800 바이트
  • 깊이/스텐실 버퍼: 1280 X 720 X 4 = 3,686,400 바이트
  • 총합: 11,059,200 바이트 = 10.54 MB (버럭! 0.54메가가 넘다니!)
물론 이런 문제를 해결하기 위해 Predicated Tiling이라는 방법을 사용할 수 있습니다. 하지만 이건 성능 상의 문제도 있고 PS3나 PC 등의 다른 플랫폼도 동시에 지원하는 게임에서 한쪽 플랫폼에만 특화된 코드를 개발하는 일에 인력을 투입하는 것도 좀 돈낭비란 생각이 들어서.... 그냥 저희 멋대로 좌우 40픽셀씩만 잘라냈습니다. 그래서 스페이스마린 Xbox 360 버전의 해상도는 1200 X 720입니다.... -_-..... 이렇게 해서 다시 메모리 사용량을 계산하면 10MB가 조금 안됩니다.

  • 렌더타겟: 1200 X 720 X 8 = 6,912,000바이트
  • 깊이/스텐실 버퍼: 1200 X 720 X 4 = 3,456,000 바이트
  • 총합: 10,368,000 바이트 = 9.89 MB

하지만 최종 TV에 등장하는 해상도는 여전히 1280 x 720입니다. 내부적으로 모든 렌더링을 1200 X 720으로 한 뒤 마지막 단계에서 그냥 1280 x 720으로 업샘플(upsample) 해줍니다... Xbox 360 하드웨어 자체에서 업샘플링을 지원해 주는걸로 기억합니다...품질도 괜찮은 편이고요.

PS3의 ZCULL 메모리
PS3에는 EDRAM같은 건 없습니다. 따라서 Xbox 360에 비해 렌더타겟에 픽셀들을 뿌려주는게 확실히 느립니다. 그 대신 PS3에는 Xbox 360에는 없는 ZCull이라는게 있는데요. ZCull은 계층적 깊이버퍼(Hierarchical Depth Buffer)와 하는 일이 비슷합니다. 보통 깊이 테스트를 통한 픽셀 rejection은 픽셀쉐이더가 실행된 뒤에 하거든요. 그래서 깊이 테스트에 실패하던 말던 픽셀쉐이더를 돌리느라 GPU 사이클을 낭비하곤 하지요.  '깊이테스트에 실패할거면 차라리 픽셀쉐이더조차 돌리지 말자'라는 개념으로 ATI가 추가한게 Hi-Z(계층적깊이)구요. 아마 이게 특허가 걸려있어서 NVidia에서는 그대신 ZCull을 추가하지 않았나 싶습니다. 참고로 Xbox 360에 들어가는 GPU가 ATI, PS3에 들어가는 GPU가 NVidia입니다.

사실 ZCull과 EDRAM은 하는 짓 자체가 전혀 틀린데 그래도 공통점 하나가 있습니다. ZCull도 하드웨어 자체에 붙어있는 메모리가 있죠. 물론 당연 그에 따라 제약도 있을거고.... 물론 EDRAM처럼 렌더타겟의 비트수만큼의 MB를 잡아먹진 않습니다. 그대신 자체적으로 깊이만 판단하면 되니까 그냥 어느정도 해상도까지만 지원해주죠. 이 어느정도 해상도라는게 대략 2048 x 1536입니다. 이정도면 사실 왠만해선 충분한 해상도지만 Cascade Shadow Map 기법에서 cascade를 렌더타겟 하나에 뭉쳐놓으려고 할 때 문제가 생기곤 하죠. 각 cascade가 1024 x 1024고 총 4개의 cascade를 사용한다면 렌더타겟의 크기가 2048 x 2048이 될테니까요.

물론 ZCull이 지원하는 해상도를 넘는 렌더타겟을 사용해도 최종결과는 동일합니다. 즉 뻗지 않습니다.... -_-..... Xbox 360의 EDRAM과는 달리 다 제대로 돌고 결과도 제대론데 문제는 성능이 개떡이 된다는 거죠. PS3의 픽셀쉐이더 속도가 Xbox 360에 비해 느린 것이 보통이라 이 ZCull이 제대로 작동되냐 마냐에 따라 프레임수가 확 차이가 납니다. 소니측에서도 성능향상 방법 1번으로 꼽는게 'ZCull 잘 주물러주기'입니다. 물론 단지 해상도뿐만이 아니라 다른 조건들이 맞아야만 ZCull이 활성화되서 좀 더 다루기 까다로운 것도 있지만..... 역시 PS3는 참 까탈스럽습니다.. ㅎ

어쨌든 이 해상도 꾸겨 맞출려고, 한 때는 cascade의 크기를 768 x 768로 제한했었고... (이러면 카스케이드 4개를 렌더타겟 하나에 뭉쳐도 1536 x 1536이니까요.) 나중에는 차라리 Deferred Shadow라는 기법을 이용해서 이 제한을 피해갔습니다. (물론 디퍼드 샤도우를 사용한 이유는 인접 카스케이드 맵의 혼합을 통한 그림자 품질개선이 주 목적이었습니다.)


대충 제 생각/소망
ZCull이나 EDRAM이나 모두 훌륭한 아이디어임에는 분명합니다. 이거 없었으면 저희 게임에서 이 정도로 성능뽑아줄 수도 없었고요.

다만 EDRAM이 ZCull처럼 해상도에 대해 좀 너그러웠으면 하는 바램이 있습니다. 해상도 지원안되는거면 그냥 성능을 줄여도 좋으니 화면에는 보이는 결과는 옳게? 저희처럼 수백만 달라 들어가는 게임이 아니라면 그 정도 성능이 필요할리가 없거든요. (아님 EDRAM사이즈를 엄청 크게 줘서 콘솔 제조원가를 올린뒤, 그걸 게이머들이 내게 하거나?.... 뭔가 이 옵션은.... 안될거 같죠?  -_- )

그리고 PS3쪽에 바라는 건 ZCull의 까탈을 좀 줄여주거나.... 까탈을 부리고 싶으면 제대로 알려주기라도 하라는... 소니에서 제공하는 프로파일러에서 캡춰하지 않는한 ZCull이 도는지 아닌지 알수가 없어요... 잘 돌던게 다른 프로그래머 실수로 갑자기 고장나도 몇 달 지나서야 발견하고.... (아님 이 해상도 제한을 높이고 콘솔기기를 비싼 값에 팔던가.....? 역시 돈이 문제입니다... -_-  )


포프였습니다.
 

댓글을 달아 주세요